home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TPUG - Toronto PET Users Group
/
TPUG Users Group CD
/
TPUG Users Group CD.iso
/
CRS
/
crs49.d81
/
hack8b.sfx
/
issue8b
Wrap
Text File
|
1990-02-12
|
91KB
|
2,422 lines
╨LOTTING A POINT
----------------
╔N THE LINE ROUTINE PRESENTED EARLIER, THE NEBULOUS STATEMENT ╨╨╠╧╘ WAS
WRITTEN. ╬OW WE COME TO PLOTTING A POINT IN ALL ITS GORY DETAIL.
╞OR THIS PROJECT, SPEED IS THE NAME OF THE GAME, AND FOR SPEED WE DON'T WANT
TO USE NORMAL BITMAPPED GRAPHICS. ╔NSTEAD, WE WANT TO USE CHARACTER
GRAPHICS. ╘HE ADVANTAGES OF USING A CUSTOM CHARACTER SET ARE:
- ╠ESS MEMORY
- ╙PEED OF PLOTTING
- ─OUBLE BUFFERING
- ├ONVENIENT ORGANIZATION
╘HE FIRST ADVANTAGE, LESS MEMORY, SHOULD BE CLEAR. ┴ CUSTOM CHARACTER SET
TAKES UP 2K. ┴ BITMAP, ON THE OTHER HAND, TAKES UP 8K.
╞OR THE SECOND ADVANTAGE, IT IS MUCH FASTER TO POKE A CHARACTER INTO SCREEN
MEMORY THAN IT IS TO CALCULATE AND PLOT ALL 64 BITS IN A CHARACTER. ╘HIS
WAY, ╓╔├ DOES ALL THE HARD WORK FOR US. ┴LSO, IF WE ARE CLEVER, WE CAN
EXPLOIT SEVERAL ASPECTS OF OUR CLEVERNESS TO MAKE PLOTTING A SINGLE POINT
MUCH EASIER.
├HARACTER GRAPHICS ALSO GIVE US A VERY SIMPLE MEANS OF DOUBLE BUFFERING: WE
CAN JUST PLOT INTO TWO DIFFERENT CHARACTER SETS AND TELL ╓╔├-╔╔ TO MOVE
BETWEEN THEM. ╬O RASTER INTERRUPTS HERE! ╔F THE TWO CHARACTER SETS WERE AT
$3000 AND $3800, HERE IS HOW TO SWITCH BETWEEN THEM:
╠─┴ ╓═├╙┬ ;╓═├╙┬=$─018
┼╧╥ #%00000010 ;╞LIP THE BIT
╙╘┴ ╓═├╙┬
╘RUE, CLEARING THE BUFFER EACH TIME IS A BIT SLOW, BUT FOR OUR PURPOSES IT
WILL DO JUST FINE.
╘HE LAST IS LESS OBVIOUS. ┴ NORMAL HIRES BITMAP IS ORGANIZED LIKE THE
FOLLOWING:
00 08 ...
01 09
02 0┴
... ...
07 0╞
WHERE THE NUMBER REPRESENTS THE OFFSET OF THE BYTE. ╘HIS IS FINE FOR SOME
THINGS, BUT CALCULATING THE POSITION OF A PIXEL IS TRICKY. ╫ITH A CHARACTER
MAP, WE CAN REPRESENT OUR DATA ANY WAY WE WANT. ╔N PARTICULAR, WE CAN
ORGANIZE OUR BITMAP TO LOOK LIKE THE FOLLOWING:
00 80 ...
01 81
02 82
... ...
7─ ╞─
7┼ ╞┼
7╞ ╞╞ ...
╧R, IN GRAPHIC FORM
@╨... ETC.
┴╤
┬╥
├╙
..
╧<- (THE BACK-ARROW)
╫HAT WE HAVE DONE IS, INSTEAD OF PUTTING CHARACTERS SIDE-BY-SIDE LIKE A
HIRES BITMAP DOES, WE PUT THEM ON TOP OF EACH OTHER. ╘HE ABOVE REPRESENTS A
16X16 CHARACTER ARRAY, WHICH IS A 128X128 PIXEL ARRAY. ╬OW THE Y-COORDINATE
IS A DIRECT INDEX INTO THE ROW WE ARE IN. ╘HAT IS, BASE+┘ = MEMORY LOCATION
OF POINT.
╘HIS BRINGS US TO THE PRIMARY DISADVANTAGE OF USING A CHARACTER SET: OUR
PICTURES ARE PRETTY SMALL. ╘┴╬╙╙┴┴╞╠.
╬OW WE COULD JUST GO MERRILY PLOTTING INTO OUR CHARACTER BITMAP, BUT AS
USUAL A LITTLE THOUGHT CAN YIELD SOME IMPRESSIVE RETURN. ╘HE FIRST THING TO
NOTICE IS THAT THE MAXIMUM VALUE FOR Y IS 127; THE ONLY THING THAT SETS THE
HIGH BIT IS THE X-COORDINATE, AND THEN ONLY WHEN IT CROSSES A COLUMN (JUST
LOOK AT THE ABOVE MEMORY MAP IF YOU DON'T SEE IT).
╘HEREFORE, IF WE COULD KEEP TRACK OF THE BIT POSITION OF X, WE COULD TELL
WHEN X CROSSED A COLUMN, AND JUST ADD 128 TO THE BASE ADDRESS. ╬OT ONLY
THAT, BUT WE ALSO KNOW TO INCREASE THE HIGH BYTE OF THE POINTER BY ONE WHEN
WE HAVE CROSSED TWO COLUMNS.
╘HE LOGIC IS AS FOLLOWS:
- ╞IND THE BIT PATTERN FOR A GIVEN X (FOR SPEED, USE A TABLE)
- ╔F IT IS 10000000 THEN WE HAVE JUMPED A COLUMN
- ╔F THE COLUMN WE ARE IN DOESN'T HAVE THE HIGH BIT SET
IN THE LOW BYTE OF THE POINTER TO THE BASE OF THE COLUMN,
THEN SET THE HIGH BIT (ADD 128)
- ╧THERWISE, SET THE HIGH BIT TO ZERO (ADD 128), AND INCREASE
THE HIGH BYTE OF THE COLUMN POINTER (STEP INTO THE NEXT PAGE).
╚ERE IS (MORE OR LESS) THE CODE:
╔N ┬┴╙╔├:
2000 REM BP(X) CONTAINS BIT POSITION FOR X
2010 IF INT(X/8) = X/8 THEN BASE=BASE+128
2020 POKE BASE+Y, (PEEK(BASE+Y) OR BP(X))
╔N ASSEMBLY:
╠─┴ ┬╔╘╨,╪ 4 ;╠OAD THE BIT PATTERN FROM A TABLE
┬╨╠ ├╧╬╘ 3 2 ;╙TILL IN THE SAME COLUMN?
┼╧╥ $╠╧ 3 ;╔F NOT, ADD 128 TO THE LOW BYTE
╙╘┴ $╠╧ 3
┬═╔ ├╧╬╘ 3 2 ;╔F THE HIGH BIT IS SET, STAY IN THE SAME PAGE
╔╬├ $╚╔ 5 ;╧THERWISE POINT TO THE NEXT PAGE
╠─┴ #$128 2 ;╫E STILL NEED THE BIT PATTERN FOR X!
├╧╬╘ ╧╥┴ ($╠╧),┘ 5
╙╘┴ ($╠╧),┘ 6 ;╨LOT THE POINT
--------
├YCLE COUNT: 18 26 32
╘HEREFORE, IT TAKES 18 CYCLES TO PLOT A POINT, 26 CYCLES TO JUMP A COLUMN,
AND 32 CYCLES TO JUMP A PAGE. ╧VER 16 POINTS, THIS AVERAGES 19.375 CYCLES.
╫HEN COMBINED WITH THE EARLIER LINE DRAWING ROUTINE, THIS GIVES AN AVERAGE
TIME OF 38 CYCLES OR SO (WITH A BEST TIME OF 34 CYCLES); SIX OF THOSE CYCLES
ARE FOR ╨╚┴ AND ╨╠┴, SINCE THE LINE DRAWING ROUTINE USES ┴ FOR OTHER THINGS.
╠IKE MOST OF THE CODE, YOU CAN IMPROVE ON THIS METHOD IF YOU THINK ABOUT IT
A LITTLE. ═OST OF THE TIME IS SPENT CHECKING THE SPECIAL CASES, SO HOW CAN
YOU AVOID THEM? ═AYBE IF WE DO ANOTHER ARTICLE, WE'LL SHOW YOU OUR
SOLUTION(S).
╬OW, THIS METHOD HAS A FEW SUBTLETIES ABOUT IT. ╞IRST, WHAT HAPPENS IF THE
FIRST POINT TO BE PLOTTED IS X=0, OR X=8? ╘HE ABOVE ROUTINE WILL INCREASE
THE BASE POINTER RIGHT OFF THE BAT. ╘HIS CASE NEEDS TO BE TAKEN CARE OF.
╙ECOND, THE ABOVE ASSUMES THAT YOU ALWAYS TAKE A STEP IN X. ╫HAT HAPPENS IF
WE ARE TAKING A BIG STEP IN Y? ╠ET'S SAY THAT WE TAKE TEN STEPS IN Y FOR
EVERY STEP IN X. ╫HAT WILL THE ABOVE PLOTTER DO IF X TAKES A STEP ACROSS A
COLUMN, AND THEN DOESN'T CHANGE FOR A WHILE? ╠OOK TO THE SOURCE CODE FOR ONE
SOLUTION TO THIS PROBLEM.
╙O THAT'S ALL THERE IS TO IT!
╨OST ╙CRIPT
-----------
╘HAT'S ALL THERE IS TO IT. ╫ELL, ╧╦, THERE ARE A FEW DETAILS WE LEFT OUT,
BUT YOU CAN FIGURE THEM OUT ON YOUR OWN. ┘OU CAN ALWAYS LOOK TO THE SOURCE
CODE TO SEE HOW WE OVERCAME THE SAME PROBLEM. ╘HE PROGRAM IS SET UP IN A
WAY THAT YOU CAN EXPERIMENT AROUND WITH THE PROJECTION PARAMETERS D AND Z0,
TO SEE WHAT CHANGING THEM DOES TO THE MATH.
╫HAT'S NEXT? ╔N THE FUTURE YOU WILL UNDOUBTABLY SEE LOTS OF THINGS FROM
╟EORGE AND MYSELF, BOTH THE WRITTEN WORD AND THE CODED BYTE. ═AYBE WE WILL
SEE SOMETHING FROM YOU AS WELL?
─A ├ODE
-------
********************************
*..............................*
*.╙TEPHEN.╩UDD.................*
*.╟EORGE.╘AYLOR................*
*.╙TARTED:.7/11/94.............*
*.╞INISHED:.7/19/94............*
*..............................*
*.╫ELL,.IF.ALL.GOES.WELL.THIS..*
*.PROGRAM.WILL.ROTATE.A.CUBE...*
*..............................*
*.╘HIS.PROGRAM.IS.INTENDED.TO..*
*.ACCOMPANY.THE.ARTICLE.IN.....*
*.├=╚ACKING,.╩ULY.94.ISSUE.....*
*.╞OR.DETAILS.ON.THIS.PROGRAM,.*
*.READ.THE.ARTICLE!............*
*..............................*
*.╫RITE.TO.US!.................*
*..............................*
*.UN(BEE)MO....................*
*..............................*
*.VI...........................*
*.N(IN)G.......................*
*.ARE(TH.......................*
*.E)YOU(O......................*
*.NLY).........................*
*..............................*
*.ASL(ROSE)EEP.................*
*..............E.E.CUMMINGS....*
*..............................*
*.╨.╙..╘HIS.WAS.WRITTEN.USING..*
*......═ERLIN.128...╫ITH.A.....*
*......LITTLE.MODIFICATION.IT..*
*......WILL.WORK.FINE.WITH.....*
*......═ERLIN.64...╔F.YOU......*
*......DON'T.HAVE.EITHER.......*
*......WELL,.WE.ALL.HAVE.OUR...*
*......LITTLE.FAULTS...........*
********************************
╧╥╟ $1000
*.├ONSTANTS
┬╒╞╞1 ┼╤╒ $3000 ;╞IRST.CHARACTER.SET
┬╒╞╞2 ┼╤╒ $3800 ;╙ECOND.CHARACTER.SET
┬╒╞╞┼╥ ┼╤╒ $┴3 ;╨RESUMABLY.THE.TAPE.WON'T.BE.RUNNING
╪1 ┼╤╒ $╞┬ ;╨OINTS.FOR.DRAWING.A.LINE
┘1 ┼╤╒ $╞├ ;╘HESE.ZERO.PAGE.ADDRESSES
╪2 ┼╤╒ $╞─ ;DON'T.CONFLICT.WITH.┬┴╙╔├
┘2 ┼╤╒ $╞┼
─╪ ┼╤╒ $╞9
─┘ ┼╤╒ $╞┴
╘┼═╨1 ┼╤╒ $╞┬ ;╧F.COURSE,.COULD.CONFLICT.WITH.X1
╘┼═╨2 ┼╤╒ $╞├ ;╘EMPORARY.VARIABLES
┴├├ ┼╤╒ $╞┬ ;╘HESE.FOUR.VARIABLES.ARE.USED
┴╒╪ ┼╤╒ $╞├ ;BY.THE.MULTIPLICATION.ROUTINE
┼╪╘ ┼╤╒ $╞─
╥┼═ ┼╤╒ $╞┼
┌╘┼═╨ ┼╤╒ $02 ;╒SED.FOR.BUFFER.SWAP...─ON'T.TOUCH.
┴╬╟═┴╪ ┼╤╒ 120 ;╘HERE.ARE.2*PI/ANGMAX.ANGLES
╧╞╞╙┼╘ ┼╤╒ 6 ;╞LOAT.OFFSET:.X=XACTUAL*2^OFFSET
*.╓╔├
╓═├╙┬ ┼╤╒ $─018
┬╦╟╬─ ┼╤╒ $─020
┬╧╥─┼╥ ┼╤╒ $─021
╙╙╘┴╥╘ ┼╤╒ 1344 ;ROW.9.IN.SCREEN.MEMORY.AT.1024
*.╦ERNAL
├╚╥╧╒╘ ┼╤╒ $╞╞─2
╟┼╘╔╬ ┼╤╒ $╞╞┼4
***.═ACROS
═╧╓┼ ═┴├
╠─┴ ]1
╙╘┴ ]2
<<<
╟┼╘╦┼┘ ═┴├ ;╫AIT.FOR.A.KEYPRESS
╫┴╔╘ ╩╙╥ ╟┼╘╔╬
├═╨ #00
┬┼╤ ╫┴╔╘
<<<
─┼┬╒╟ ═┴├ ;╨RINT.A.CHARACTER
. ─╧.0 ;─ON'T.ASSEMBLE
╠─┴ #]1
╩╙╥ ├╚╥╧╒╘
>>> ╟┼╘╦┼┘ ;┴ND.WAIT.TO.CONTINUE
├═╨ #'S' ;═Y.SECRECT.SWITCH.KEY
┬╬┼ ╠1
╩╙╥ ├╠┼┴╬╒╨
╩═╨ ─╧╬┼
╠1 ├═╨ #'X' ;═Y.SECRET.ABORT.KEY
┬╬┼ ─╧╬┼
╩═╨ ├╠┼┴╬╒╨
╞╔╬
─╧╬┼ <<<
─┼┬╒╟┴ ═┴├
─╧.0
╠─┴ ]1
╙╘┴ 1024
╞╔╬
─╧╬┼┴ <<<
╙┼╘┬╒╞ ═┴├ ;╨UT.BUFFERS.WHERE.THEY.CAN.BE.HURT
╠─┴ #00
╙╘┴ ┬╒╞╞┼╥
╠─┴ ┌╘┼═╨ ;ZTEMP.CONTAINS.THE.HIGH.BYTE.HERE
╙╘┴ ┬╒╞╞┼╥+1
<<<
*-------------------------------
╠─┴ #$00
╙╘┴ ┬╦╟╬─
╙╘┴ ┬╧╥─┼╥
╠─┴ ╓═├╙┬
┴╬─ #%00001111 ;╙CREEN.MEMORY.TO.1024
╧╥┴ #%00010000
╙╘┴ ╓═├╙┬
╠─┘ #00
╠─┴ #<╘╘┼╪╘
╙╘┴ ╘┼═╨1
╠─┴ #>╘╘┼╪╘
╙╘┴ ╘┼═╨2
╩═╨ ╘╔╘╠┼
╘╘┼╪╘ ╚┼╪ 9305111111 ;CLEAR.SCREEN,.WHITE,.CRSR.DN
╘╪╘ '...............CUBE3D',0D,0D
╘╪╘ '.................BY',0D
╚┼╪ 9╞ ;CYAN
╘╪╘ '....STEPHEN.JUDD'
╚┼╪ 99
╘╪╘ '....GEORGE.TAYLOR',0D,0D
╚┼╪ 9┬
╘╪╘ '..CHECK.OUT.THE.JULY.94.ISSUE.OF',0D
╚┼╪ 96
╘╪╘ '..C=HACKING'
╚┼╪ 9┬
╘╪╘ '.FOR.MORE.DETAILS!',0D
╚┼╪ 0─1─1─9┼12
╘╪╘ 'F1/F2',92
╘╪╘ '.-.INC/DEC.X-ROTATION',0D
╚┼╪ 1─1─12
╘╪╘ 'F3/F4',92
╘╪╘ '.-.INC/DEC.Y-ROTATION',0D
╚┼╪ 1─1─12
╘╪╘ 'F5/F6',92
╘╪╘ '.-.INC/DEC.Z-ROTATION',0D
╚┼╪ 1─1─12
╘╪╘ 'F7',92
╘╪╘ '.RESETS',0D
╘╪╘ '..PRESS.Q.TO.QUIT',0D
╚┼╪ 0─05
╘╪╘ '......PRESS.ANY.KEY.TO.BEGIN',0D
╚┼╪ 00
╘╔╘╠┼ ╠─┴ (╘┼═╨1),┘
┬┼╤ :├╧╬╘
╩╙╥ ├╚╥╧╒╘
╔╬┘
┬╬┼ ╘╔╘╠┼
╔╬├ ╘┼═╨2
╩═╨ ╘╔╘╠┼
:├╧╬╘ >>> ╟┼╘╦┼┘
****.╙ET.UP.TABLES(?)
*.╘ABLES.ARE.CURRENTLY.SET.UP.IN.┬┴╙╔├
*.AND.BY.THE.ASSEMBLER.
╘┴┬╠┼╙
****.├LEAR.SCREEN.AND.SET.UP."BITMAP"
╙┼╘╒╨ ╠─┴ #147
╩╙╥ ├╚╥╧╒╘
╠─┴ #<╙╙╘┴╥╘
┴─├ #12 ;╘HE.GOAL.IS.TO.CENTER.THE.GRAPHICS
╙╘┴ ╘┼═╨1 ;├OLUMN.12
╠─┴ #>╙╙╘┴╥╘ ;╥OW.9
╙╘┴ ╘┼═╨1+1 ;╙╙╘┴╥╘.POINTS.TO.ROW.9
╠─┴ #00
╠─┘ #00
╠─╪ #00 ;X.WILL.COUNT.16.ROWS.FOR.US
├╠├
:╠╧╧╨ ╙╘┴ (╘┼═╨1),┘
╔╬┘
┴─├ #16
┬├├ :╠╧╧╨
├╠├
╠─┴ ╘┼═╨1
┴─├ #40 ;╬EED.TO.ADD.40.TO.THE.BASE.POINTER
╙╘┴ ╘┼═╨1 ;╘O.JUMP.TO.THE.NEXT.ROW
╠─┴ ╘┼═╨1+1
┴─├ #00 ;╘AKE.CARE.OF.CARRIES
╙╘┴ ╘┼═╨1+1
╠─┘ #00
╔╬╪
╘╪┴ ;╪.IS.ALSO.AN.INDEX.INTO.THE.CHARACTER.NUMBER
├╨╪ #16
┬╬┼ :╠╧╧╨ ;╬EED.TO.DO.IT.16.TIMES
>>> ─┼┬╒╟,'2'
****.╙ET.UP.BUFFERS
╠─┴ #<┬╒╞╞1
╙╘┴ ┬╒╞╞┼╥
╠─┴ #>┬╒╞╞1
╙╘┴ ┬╒╞╞┼╥+1
╙╘┴ ┌╘┼═╨ ;ZTEMP.WILL.MAKE.LIFE.SIMPLE.FOR.US
╠─┴ ╓═├╙┬
┴╬─ #%11110001 ;╙TART.HERE.SO.THAT.SWAP.BUFFERS.WILL.WORK.RIGHT
╧╥┴ #%00001110
╙╘┴ ╓═├╙┬
****.╙ET.UP.INITIAL.VALUES
╔╬╔╘ ╠─┴ #00
╙╘┴ ─╙╪
╙╘┴ ─╙┘
╙╘┴ ─╙┌
╙╘┴ ╙╪
╙╘┴ ╙┘
╙╘┴ ╙┌
>>> ─┼┬╒╟,'4'
*-------------------------------
*.═AIN.LOOP
****.╟ET.KEYPRESS
═┴╔╬
╦╨╥┼╙╙ ╩╙╥ ╟┼╘╔╬
├═╨ #133 ;╞1?
┬╬┼ :╞2
╠─┴ ─╙╪
├═╨ #┴╬╟═┴╪/2 ;╬O.MORE.THAN.PI
┬┼╤ :├╧╬╘
╔╬├ ─╙╪ ;OTHERWISE.INCREASE.X-ROTATION
╩═╨ :├╧╬╘
:╞2 ├═╨ #137 ;╞2?
┬╬┼ :╞3
╠─┴ ─╙╪
┬┼╤ :├╧╬╘
─┼├ ─╙╪
╩═╨ :├╧╬╘
:╞3 ├═╨ #134
┬╬┼ :╞4
╠─┴ ─╙┘
├═╨ #┴╬╟═┴╪/2
┬┼╤ :├╧╬╘
╔╬├ ─╙┘ ;╔NCREASE.Y-ROTATION
╩═╨ :├╧╬╘
:╞4 ├═╨ #138
┬╬┼ :╞5
╠─┴ ─╙┘
┬┼╤ :├╧╬╘
─┼├ ─╙┘
╩═╨ :├╧╬╘
:╞5 ├═╨ #135
┬╬┼ :╞6
╠─┴ ─╙┌
├═╨ #┴╬╟═┴╪/2
┬┼╤ :├╧╬╘
╔╬├ ─╙┌ ;Z-ROTATION
╩═╨ :├╧╬╘
:╞6 ├═╨ #139
┬╬┼ :╞7
╠─┴ ─╙┌
┬┼╤ :├╧╬╘
─┼├ ─╙┌
╩═╨ :├╧╬╘
:╞7 ├═╨ #136
┬╬┼ :╤
╩═╨ ╔╬╔╘
:╤ ├═╨ #'Q' ;Q.QUITS
┬╬┼ :├╧╬╘
╩═╨ ├╠┼┴╬╒╨
:├╧╬╘
*.>>>.─┼┬╒╟,'5'
****.╒PDATE.ANGLES
╒╨─┴╘┼ ├╠├
╠─┴ ╙╪
┴─├ ─╙╪
├═╨ #┴╬╟═┴╪ ;┴RE.WE.>=.MAXIMUM.ANGLE?
┬├├ :├╧╬╘1
╙┬├ #┴╬╟═┴╪ :╔F SO, RESET
:├╧╬╘1 ╙╘┴ ╙╪
├╠├
╠─┴ ╙┘
┴─├ ─╙┘
├═╨ #┴╬╟═┴╪
┬├├ :├╧╬╘2
╙┬├ #┴╬╟═┴╪ ;╙AME.DEAL
:├╧╬╘2 ╙╘┴ ╙┘
├╠├
╠─┴ ╙┌
┴─├ ─╙┌
├═╨ #┴╬╟═┴╪
┬├├ :├╧╬╘3
╙┬├ #┴╬╟═┴╪
:├╧╬╘3 ╙╘┴ ╙┌
****.╥OTATE.COORDINATES
╥╧╘┴╘┼
***.╞IRST,.CALCULATE.T1,T2,...,T10
**.╘WO.MACROS.TO.SIMPLIFY.OUR.LIFE
┴──┴ ═┴├ ;┴DD.TWO.ANGLES.TOGETHER
├╠├
╠─┴ ]1
┴─├ ]2
├═╨ #┴╬╟═┴╪ ;╔S.THE.SUM.>.2*PI?
┬├├ ─╧╬┼
╙┬├ #┴╬╟═┴╪ ;╔F.SO,.SUBTRACT.2*PI
─╧╬┼ <<<
╙╒┬┴ ═┴├ ;╙UBTRACT.TWO.ANGLES
╙┼├
╠─┴ ]1
╙┬├ ]2
┬├╙ ─╧╬┼
┴─├ #┴╬╟═┴╪ ;╧OPS,.WE.NEED.TO.ADD.2*PI
─╧╬┼ <<<
**.╬OW.CALCULATE.T1,T2,ETC.
>>> ╙╒┬┴,╙┘;╙┌
╙╘┴ ╘1 ;T1=SY-SZ
>>> ┴──┴,╙┘;╙┌
╙╘┴ ╘2 ;T2=SY+SZ
>>> ┴──┴,╙╪;╙┌
╙╘┴ ╘3 ;T3=SX+SZ
>>> ╙╒┬┴,╙╪;╙┌
╙╘┴ ╘4 ;T4=SX-SZ
>>> ┴──┴,╙╪;╘2
╙╘┴ ╘5 ;T5=SX+T2
>>> ╙╒┬┴,╙╪;╘1
╙╘┴ ╘6 ;T6=SX-T1
>>> ┴──┴,╙╪;╘1
╙╘┴ ╘7 ;T7=SX+T1
>>> ╙╒┬┴,╘2;╙╪
╙╘┴ ╘8 ;T8=T2-SX
>>> ╙╒┬┴,╙┘;╙╪
╙╘┴ ╘9 ;T9=SY-SX
>>> ┴──┴,╙╪;╙┘
╙╘┴ ╘10 ;T10=SX+SY
*.┼T.VOILA!
***.╬EXT,.CALCULATE.┴,┬,├,...,╔
**.┴NOTHER.USEFUL.LITTLE.MACRO
─╔╓2 ═┴├ ;─IVIDE.A.SIGNED.NUMBER.BY.2
;╔T.IS.ASSUMED.THAT.THE.NUMBER
┬╨╠ ╨╧╙ ;IS.IN.THE.ACCUMULATOR
├╠├
┼╧╥ #$╞╞ ;╫E.NEED.TO.UN-NEGATIVE.THE.NUMBER
┴─├ #01 ;BY.TAKING.IT'S.COMPLEMENT
╠╙╥ ;DIVIDE.BY.TWO
├╠├
┼╧╥ #$╞╞
┴─├ #01 ;═AKE.IT.NEGATIVE.AGAIN
╩═╨ ─╧╬┼─╔╓
╨╧╙ ╠╙╥ ;╬UMBER.IS.POSITIVE
─╧╬┼─╔╓ <<<
═╒╠2 ═┴├ ;═ULTIPLY.A.SIGNED.NUMBER.BY.2
┬╨╠ ╨╧╙═
├╠├
┼╧╥ #$╞╞
┴─├ #$01
┴╙╠
├╠├
┼╧╥ #$╞╞
┴─├ #$01
╩═╨ ─╧╬┼═╒╠
╨╧╙═ ┴╙╠
─╧╬┼═╒╠ <<<
**.╬OTE.THAT.WE.ARE.CURRENTLY.MAKING.A.MINOR.LEAP
**.OF.FAITH.THAT.NO.OVERFLOWS.WILL.OCCUR.
:├┴╠├┴ ├╠├
╠─╪ ╘1
╠─┴ ├╧╙,╪
╠─╪ ╘2
┴─├ ├╧╙,╪
╙╘┴ ┴11 ;┴=(COS(T1)+COS(T2))/2
:├┴╠├┬ ╠─╪ ╘1
╠─┴ ╙╔╬,╪
╙┼├
╠─╪ ╘2
╙┬├ ╙╔╬,╪
╙╘┴ ┬12 ;┬=(SIN(T1)-SIN(T2))/2
:├┴╠├├ ╠─╪ ╙┘
╠─┴ ╙╔╬,╪
>>> ═╒╠2
╙╘┴ ├13 ;├=SIN(SY)
:├┴╠├─ ╙┼├
╠─╪ ╘8
╠─┴ ├╧╙,╪
╠─╪ ╘7
╙┬├ ├╧╙,╪
╙┼├
╠─╪ ╘5
╙┬├ ├╧╙,╪
├╠├
╠─╪ ╘6
┴─├ ├╧╙,╪ ;─I=(COS(T8)-COS(T7)+COS(T6)-COS(T5))/2
>>> ─╔╓2
├╠├
╠─╪ ╘3
┴─├ ╙╔╬,╪
╙┼├
╠─╪ ╘4
╙┬├ ╙╔╬,╪
╙╘┴ ─21 ;─=(SIN(T3)-SIN(T4)+─I)/2
:├┴╠├┼ ╙┼├
╠─╪ ╘5
╠─┴ ╙╔╬,╪
╠─╪ ╘6
╙┬├ ╙╔╬,╪
╙┼├
╠─╪ ╘7
╙┬├ ╙╔╬,╪
╙┼├
╠─╪ ╘8
╙┬├ ╙╔╬,╪ ;┼I=(SIN(T5)-SIN(T6)-SIN(T7)-SIN(T8))/2
>>> ─╔╓2
├╠├
╠─╪ ╘3
┴─├ ├╧╙,╪
├╠├
╠─╪ ╘4
┴─├ ├╧╙,╪
╙╘┴ ┼22 ;┼=(COS(T3)+COS(T4)+┼I)/2
:├┴╠├╞ ╠─╪ ╘9
╠─┴ ╙╔╬,╪
╙┼├
╠─╪ ╘10
╙┬├ ╙╔╬,╪
╙╘┴ ╞23 ;╞=(SIN(T9)-SIN(T10))/2
:├┴╠├╟ ╠─╪ ╘6
╠─┴ ╙╔╬,╪
╙┼├
╠─╪ ╘8
╙┬├ ╙╔╬,╪
╙┼├
╠─╪ ╘7
╙┬├ ╙╔╬,╪
╙┼├
╠─╪ ╘5
╙┬├ ╙╔╬,╪ ;╟I=(SIN(T6)-SIN(T8)-SIN(T7)-SIN(T5))/2
>>> ─╔╓2
├╠├
╠─╪ ╘4
┴─├ ├╧╙,╪
╙┼├
╠─╪ ╘3
╙┬├ ├╧╙,╪
╙╘┴ ╟31 ;╟=(COS(T4)-COS(T3)+╟I)/2
>>> ─┼┬╒╟┴,╟31
>>> ─┼┬╒╟,'G'
:├┴╠├╚ ├╠├
╠─╪ ╘6
╠─┴ ├╧╙,╪
╠─╪ ╘7
┴─├ ├╧╙,╪
╙┼├
╠─╪ ╘5
╙┬├ ├╧╙,╪
╙┼├
╠─╪ ╘8
╙┬├ ├╧╙,╪ ;╚I=(COS(T6)+COS(T7)-COS(T5)-COS(T8))/2
>>> ─╔╓2
├╠├
╠─╪ ╘3
┴─├ ╙╔╬,╪
├╠├
╠─╪ ╘4
┴─├ ╙╔╬,╪
╙╘┴ ╚32 ;╚=(SIN(T3)+SIN(T4)+╚I)/2
:╫╚┼╫ ├╠├
╠─╪ ╘9
╠─┴ ├╧╙,╪
╠─╪ ╘10
┴─├ ├╧╙,╪
╙╘┴ ╔33 ;╔=(COS(T9)+COS(T10))/2
**.╔T'S.ALL.DOWNHILL.FROM.HERE.
**.╥OTATE,.PROJECT,.AND.STORE.THE.POINTS
─╧╫╬╚╔╠╠ ╠─┴ ┴11 ;╘HIS.IS.GETTING.TO.BE.A.REAL.MESS
╙╘┴ ╘┴
╠─┴ ┬12 ;╘HE.REASON.THIS.IS.DONE
╙╘┴ ╘┬ ;IS.TO.MAKE.THE.CODE.A.LITTLE
╠─┴ ├13 ;EASIER.TO.READ.(AND.DEBUG!)
╙╘┴ ╘├
╠─┴ ─21 ;╘HESE.ARE.ALL.TEMPORARY.LOCATIONS
╙╘┴ ╘─ ;╒SED.BY.THE.PROJECTION.SUBROUTINE.
╠─┴ ┼22
╙╘┴ ╘┼ ;╧THERWISE,.THERE.WOULD.BE.EIGHT
╠─┴ ╞23 ;LONG.ROUTINES.HERE.
╙╘┴ ╘╞
╠─┴ ╟31 ;┬UT.IT.WOULD.BE.SIGNIFICANTLY.FASTER
╙╘┴ ╘╟
╠─┴ ╚32
╙╘┴ ╘╚
╠─┴ ╔33
╙╘┴ ╘╔
*.┴.NEAT.MACRO
╬┼╟ ═┴├ ;├HANGE.THE.SIGN.OF.A.TWO'S.COMPLEMENT
├╠├
╠─┴ ]1 ;NUMBER.
┼╧╥ #$╞╞
┴─├ #$01
<<<
*.╨1=[1.1.1]
╩╙╥ ╨╥╧╩┼├╘ ;╒NROLL.THIS.WHOLE.THING
╠─╪ ╘╪1 ;(SORRY.ABOUT.THESE.TWO.LINES)
╠─┘ ╘┘1 ;(SEE.╨╥╧╩┼├╘.FOR.REASON.WHY)
╙╘╪ ╨1╪ ;╞OR.A.PRETTY.BIG.SPEED.INCREASE!
╙╘┘ ╨1┘
*.╨2=[1.-1.1]
>>> ╬┼╟,┬12 ;├HANGE.THESE.ELEMENTS
╙╘┴ ╘┬
>>> ╬┼╟,┼22 ;╙INCE.Y.IS.NOW.-1
╙╘┴ ╘┼
>>> ╬┼╟,╚32
╙╘┴ ╘╚
╩╙╥ ╨╥╧╩┼├╘
╠─╪ ╘╪1
╠─┘ ╘┘1
╙╘╪ ╨2╪
╙╘┘ ╨2┘
*.╨3=[-1.-1.1]
>>> ╬┼╟,┴11
╙╘┴ ╘┴
>>> ╬┼╟,─21
╙╘┴ ╘─
>>> ╬┼╟,╟31
╙╘┴ ╘╟
╩╙╥ ╨╥╧╩┼├╘
╠─╪ ╘╪1
╠─┘ ╘┘1
╙╘╪ ╨3╪
╙╘┘ ╨3┘
*.╨4=[-1.1.1]
╠─┴ ┬12
╙╘┴ ╘┬
╠─┴ ┼22
╙╘┴ ╘┼
╠─┴ ╚32
╙╘┴ ╘╚
╩╙╥ ╨╥╧╩┼├╘
╠─╪ ╘╪1
╠─┘ ╘┘1
╙╘╪ ╨4╪
╙╘┘ ╨4┘
*.╨8=[-1.1.-1]
>>> ╬┼╟,├13
╙╘┴ ╘├
>>> ╬┼╟,╞23
╙╘┴ ╘╞
>>> ╬┼╟,╔33
╙╘┴ ╘╔
╩╙╥ ╨╥╧╩┼├╘
╠─╪ ╘╪1
╠─┘ ╘┘1
╙╘╪ ╨8╪
╙╘┘ ╨8┘
*.╨7=[-1.-1.-1]
>>> ╬┼╟,┬12
╙╘┴ ╘┬
>>> ╬┼╟,┼22
╙╘┴ ╘┼
>>> ╬┼╟,╚32
╙╘┴ ╘╚
╩╙╥ ╨╥╧╩┼├╘
╠─╪ ╘╪1
╠─┘ ╘┘1
╙╘╪ ╨7╪
╙╘┘ ╨7┘
*.╨6=[1.-1.-1]
╠─┴ ┴11
╙╘┴ ╘┴
╠─┴ ─21
╙╘┴ ╘─
╠─┴ ╟31
╙╘┴ ╘╟
╩╙╥ ╨╥╧╩┼├╘
╠─╪ ╘╪1
╠─┘ ╘┘1
╙╘╪ ╨6╪
╙╘┘ ╨6┘
*.╨5=[1.1.-1]
╠─┴ ┬12
╙╘┴ ╘┬
╠─┴ ┼22
╙╘┴ ╘┼
╠─┴ ╚32
╙╘┴ ╘╚
╩╙╥ ╨╥╧╩┼├╘
╠─╪ ╘╪1
╠─┘ ╘┘1
╙╘╪ ╨5╪
╙╘┘ ╨5┘
****.├LEAR.BUFFER
>>> ╙┼╘┬╒╞
├╠╥┬╒╞ ╠─┴ #$00 ;╨RETTY.STRAIGHTFORWARD,
╠─╪ #$08 ;╔.THINK
╠─┘ #$00
:╠╧╧╨ ╙╘┴ (┬╒╞╞┼╥),┘
╔╬┘
┬╬┼ :╠╧╧╨
╔╬├ ┬╒╞╞┼╥+1
─┼╪
┬╬┼ :╠╧╧╨
╠─┴ ┬╒╞╞┼╥+1
****.╞INALLY,.DRAW.THE.LINES.
╠─┴ ╨1╪ ;[1.1.1]
╙╘┴ ╘╪1
╠─┴ ╨1┘
╙╘┴ ╘┘1
╠─┴ ╨2╪ ;[1.-1.1]
╙╘┴ ╘╪2
╠─┴ ╨2┘
╙╘┴ ╘┘2
╩╙╥ ─╥┴╫ ;╞IRST.LINE
╠─┴ ╨3╪ ;[-1.-1.1]
╙╘┴ ╘╪1
╠─┴ ╨3┘
╙╘┴ ╘┘1
╩╙╥ ─╥┴╫ ;╙ECOND.LINE
╠─┴ ╨4╪ ;[-1.1.1]
╙╘┴ ╘╪2
╠─┴ ╨4┘
╙╘┴ ╘┘2
╩╙╥ ─╥┴╫ ;╘HIRD.LINE
╠─┴ ╨1╪ ;[1.1.1]
╙╘┴ ╘╪1
╠─┴ ╨1┘
╙╘┴ ╘┘1
╩╙╥ ─╥┴╫ ;╞OURTH.LINE...╧NE.FACE.DONE.
╠─┴ ╨5╪ ;[1.1.-1]
╙╘┴ ╘╪2
╠─┴ ╨5┘
╙╘┴ ╘┘2
╩╙╥ ─╥┴╫ ;╞IVE
╠─┴ ╨6╪ ;[1.-1.-1]
╙╘┴ ╘╪1
╠─┴ ╨6┘
╙╘┴ ╘┘1
╩╙╥ ─╥┴╫ ;╙IX
╠─┴ ╨2╪ ;[1.-1.1]
╙╘┴ ╘╪2
╠─┴ ╨2┘
╙╘┴ ╘┘2
╩╙╥ ─╥┴╫ ;╙EVEN
╠─┴ ╨7╪ ;[-1.-1.-1]
╙╘┴ ╘╪2
╠─┴ ╨7┘
╙╘┴ ╘┘2
╩╙╥ ─╥┴╫ ;┼IGHT
╠─┴ ╨3╪ ;[-1.-1.1]
╙╘┴ ╘╪1
╠─┴ ╨3┘
╙╘┴ ╘┘1
╩╙╥ ─╥┴╫ ;╬INE
╠─┴ ╨8╪ ;[-1.1.-1]
╙╘┴ ╘╪1
╠─┴ ╨8┘
╙╘┴ ╘┘1
╩╙╥ ─╥┴╫ ;╘EN
╠─┴ ╨4╪ ;[-1.1.1]
╙╘┴ ╘╪2
╠─┴ ╨4┘
╙╘┴ ╘┘2
╩╙╥ ─╥┴╫ ;┼LEVEN
╠─┴ ╨5╪ ;[1.1.-1]
╙╘┴ ╘╪2
╠─┴ ╨5┘
╙╘┴ ╘┘2
╩╙╥ ─╥┴╫ ;╘WELVE!
****.╙WAP.BUFFERS
╙╫┴╨┬╒╞ ╠─┴ ╓═├╙┬
┼╧╥ #$02 ;╨RETTY.TRICKY,.EH?
╙╘┴ ╓═├╙┬
╠─┴ #$08
┼╧╥ ┌╘┼═╨ ;ZTEMP=HIGH.BYTE.JUST.FLIPS
╙╘┴ ┌╘┼═╨ ;BETWEEN.$30.AND.$38
╩═╨ ═┴╔╬ ;┴ROUND.AND.AROUND.WE.GO...
*-------------------------------
*.╘HIS.SUBROUTINE.CALCULATES.THE.PROJECTION.OF.╪.AND.┘
╨╥╧╩┼├╘ ├╠├
╠─┴ ╘╟
┴─├ ╘╚
├╠├
┴─├ ╘╔ ;╘HIS.IS.ROTATED.┌
├╠├
┴─├ #128 ;╫E.ARE.GOING.TO.TAKE.128+Z
╘┴╪ ;╬OW.IT.IS.READY.FOR.INDEXING
╠─┴ ┌─╔╓,╪ ;╘ABLE.OF.-D/Z
╙╘┴ ┴╒╪ ;╘HIS.IS.FOR.THE.PROJECTION
╙╘┴ ╥┼═ ;═ULTIPLY.CAN.CLOBBER.┴╒╪
├╠├
╠─┴ ╘┴
┴─├ ╘┬
├╠├
┴─├ ╘├
╙╘┴ ┴├├ ;╘HIS.IS.ROTATED.X
╩╙╥ ╙═╒╠╘ ;╙IGNED.MULTIPLY.┴├├*┴╒╪/2^╧╞╞╙┼╘
├╠├
╠─┴ ┴├├
:├╧╬╘1 ┴─├ #64 ;╧FFSET.THE.COORDINATE
*.╙EE.BELOW.FOR.THE.REASON.WHY.THIS
*.NEXT.INSTRUCTION.IS.COMMENTED.OUT
*.╘┴╪..;╬OW.╪.IS.X!
╙╘┴ ╘╪1
├╠├ ;─O.THE.WHOLE.THING.AGAIN.FOR.┘
╠─┴ ╥┼═
╙╘┴ ┴╒╪
╠─┴ ╘─
┴─├ ╘┼
├╠├
┴─├ ╘╞
╙╘┴ ┴├├ ;╘HIS.IS.ROTATED.Y
╩╙╥ ╙═╒╠╘ ;╙IGNED.MULTIPLY.┴├├*┴╒╪/2^╧╞╞╙┼╘
├╠├
╠─┴ ┴├├
:├╧╬╘2 ┴─├ #64 ;╧FFSET.THE.COORDINATE
*.╞OR.SOME.COMPLETELY.UNKNOWN.REASON.TO.ME
*.THE.INSTRUCTION.BELOW.DOESN'T.WORK...╙OMEHOW
*.THE.╥╘╙.IS.MODIFYING.╪.AND.┘???
*.╘┴┘..;╙TORE.IN.┘
╙╘┴ ╘┘1
╥╘╙ ;╔.HOPE.TO.HECK.THIS.WORKS.
*-------------------------------
*.╙═╒╠╘:.8-BIT.SIGNED.(SORT-OF).MULTIPLY
*
*.┴├├*┴╒╪/2^╧╞╞╙┼╘.->.[┴├├,.┼╪╘]..16-BIT.RESULT..LO,HI
*
*.╬OTE.THAT.THIS.ROUTINE.DIVIDES.THE.END.RESULT.BY.2^╧╞╞╙┼╘
*.┘UP,.ANOTHER.MACRO.
─╔╓╧╞╞ ═┴├ ;─IVIDE.BY.THE.FLOAT.OFFSET
╠╒╨ ╧╞╞╙┼╘ ;╥EPEAT.OFFSET.TIMES
╠╙╥ ;┴.CONTAINS.HIGH.BYTE
╥╧╥ ┴├├ ;┴├├.IS.LOW.BYTE
--^
<<<
╙═╒╠╘ ├╠├
╠─┴ ┴├├ ;╞IRST,.IS.THE.RESULT.POSITIVE.OR.NEGATIVE?
┼╧╥ ┴╒╪
┬═╔ :╬┼╟
╠─┴ ┴├├ ;╘HEY.ARE.EITHER.BOTH.NEGATIVE.OR
┬╨╠ :├╧╬╘1 ;BOTH.POSITIVE
┼╧╥ #$╞╞ ;╔N.THIS.CASE,.MAKE.THEM
┴─├ #$01 ;BOTH.POSITIVE!
╙╘┴ ┴├├
>>> ╬┼╟,┴╒╪ ;╠ITTLE.MACRO.USED.EARLIER.
:├╧╬╘1 ╠─┴ #00 ;═ULTIPLY.THE.TWO.NUMBERS
╠─┘ #$09
]╠╧╧╨ ╠╙╥ ;╥EAD.THE.ARTICLE.FOR.DETAILS.
╥╧╥ ┴├├
┬├├ :═╒╠╘1 ;╧R.FIGURE.IT.OUT.YOURSELF!
├╠├
┴─├ ┴╒╪
:═╒╠╘1 ─┼┘
┬╬┼ ]╠╧╧╨
>>> ─╔╓╧╞╞ ;╥EMOVE.THIS.LINE.FOR.A.GENERAL.MULTIPLY
╙╘┴ ┼╪╘
╥╘╙
:╬┼╟ ╠─┴ ┴├├ ;╧NE.OF.THE.TWO.IS.NEGATIVE
┬═╔ :├╧╬╘2
>>> ╬┼╟,┴╒╪ ;╧THERWISE.IT'S.┴╒╪
╩═╨ :├╧╬╘3
:├╧╬╘2 ┼╧╥ #$╞╞ ;╘AKE.TWO'S.COMPLEMENT
┴─├ #$01
╙╘┴ ┴├├
:├╧╬╘3 ╠─┴ #00 ;═ULTIPLY
╠─┘ #$09
]╠╧╧╨2 ╠╙╥
╥╧╥ ┴├├
┬├├ :═╒╠╘2
├╠├
┴─├ ┴╒╪
:═╒╠╘2 ─┼┘
┬╬┼ ]╠╧╧╨2
>>> ─╔╓╧╞╞ ;┴GAIN,.DIVIDE.BY.THE.OFFSET
╙╘┴ ┼╪╘
╠─┴ ┴├├
┬╨╠ :╧╦ ;╙OMETHING.IS.REALLY.WRONG.IF.THIS.IS.NEGATIVE.
╩╙╥ ├╚╧╦┼
:╧╦ ┼╧╥ #$╞╞ ;╧THERISE,.EVERYTHING.RELEVANT.SHOULD
┴─├ #$01 ;BE.COMPLETELY.IN.THE.LOW.BYTE.
╙╘┴ ┴├├
╥╘╙ ;╔.HOPE...
*-------------------------------
*.╟ENERAL.QUESTIONABLE-VALUE.ERROR.PROCEDURE
├╚╧╦┼ ╠─╪ #00
:╠╧╧╨ ╠─┴ :├╘┼╪╘,╪
┬┼╤ :─╧╬┼
╩╙╥ ├╚╥╧╒╘
╔╬╪
╩═╨ :╠╧╧╨
:─╧╬┼ ╥╘╙
:├╘┼╪╘ ╚┼╪ 0─ ;├╥
╘╪╘ 'SOMETHING.CHOKED.:('
╚┼╪ 0─00
*-------------------------------
*.─RAWIN'.A.LINE...┴.FAHN.LAHN.
***.╙OME.USEFUL.MACROS
╨╠╧╘╨╪ ═┴├ ;PLOT.A.POINT.IN.X
╨╚┴ ;╒SE.THIS.ONE.EVERY.TIME
╠─┴ ┬╔╘╨,╪ ;╪.IS.INCREASED
┬╨╠ ├1
┼╧╥ ┬╒╞╞┼╥
╙╘┴ ┬╒╞╞┼╥
┬═╔ ├2
╔╬├ ┬╒╞╞┼╥+1
├2 ╠─┴ #%10000000
├1 ╧╥┴ (┬╒╞╞┼╥),┘
╙╘┴ (┬╒╞╞┼╥),┘
╨╠┴ ;╬EED.TO.SAVE.┴!
<<<
╨╠╧╘╨┘ ═┴├ ;╨LOT.A.POINT.IN.Y:.SIMPLER.AND.NECESSARY!
╨╚┴ ;╒SE.THIS.ONE.WHEN.YOU.JUST.INCREASE.┘
╠─┴ ┬╔╘╨,╪ ;BUT.╪.DOESN'T.CHANGE
╧╥┴ (┬╒╞╞┼╥),┘
╙╘┴ (┬╒╞╞┼╥),┘
╨╠┴
<<<
├╔╬╔╘ ═┴├ ;═ACRO.TO.INITIALIZE.THE.COUNTER
╠─┴ ]1 ;DX.OR.DY
╠╙╥
┼╧╥ #$╞╞ ;(╬OT.REALLY.TWO'S.COMPLEMENT)
┴─├ #$01 ;┴.=.256-DX/2.OR.256-DY/2
<<< ;╘HE.DX/2.MAKES.A.NICER.LOOKING.LINE
╪╙╘┼╨ ═┴├ ;═ACRO.TO.TAKE.A.STEP.IN.╪
╪╠╧╧╨ ╔╬╪
┴─├ ─┘
┬├├ ╠1
*.─O.WE.USE.╔╬┘.OR.─┼┘.HERE?
╔╞ ╔,]1 ;╔F.THE.FIRST.CHARACTER.IS.AN.'╔'
╔╬┘
┼╠╙┼
─┼┘
╞╔╬
╙┬├ ─╪
╠1 >>> ╨╠╧╘╨╪ ;┴LWAYS.TAKE.A.STEP.IN.╪
├╨╪ ╪2
┬╬┼ ╪╠╧╧╨
<<<
┘╙╘┼╨ ═┴├ ;╙AME.THING,.BUT.FOR.┘
┘╠╧╧╨ ╔╞ ╔,]1
╔╬┘
┼╠╙┼
─┼┘
├╠├ ;╓ERY.IMPORTANT!
╞╔╬
┴─├ ─╪
┬├├ ╠2
╔╬╪ ;┴LWAYS.INCREASE.╪
╙┬├ ─┘
>>> ╨╠╧╘╨╪
╩═╨ ╠3
╠2 >>> ╨╠╧╘╨┘ ;╫E.ONLY.INCREASED.┘
╠3 ├╨┘ ┘2
┬╬┼ ┘╠╧╧╨
<<<
****.╔NITIAL.LINE.SETUP
─╥┴╫ >>> ═╧╓┼,╘╪1;╪1 ;═OVE.STUFF.INTO.ZERO.PAGE
>>> ═╧╓┼,╘╪2;╪2 ;╫HERE.IT.CAN.BE.MODIFIED
>>> ═╧╓┼,╘┘1;┘1
>>> ═╧╓┼,╘┘2;┘2
>>> ╙┼╘┬╒╞ ;╬OW.WE.CAN.CLOBBER.THE.BUFFER
╙┼├ ;═AKE.SURE.X1<X2
╠─┴ ╪2
╙┬├ ╪1
┬├╙ :├╧╬╘
╠─┴ ┘2 ;╔F.NOT,.SWAP.╨1.AND.╨2
╠─┘ ┘1
╙╘┴ ┘1
╙╘┘ ┘2
╠─┴ ╪1
╠─┘ ╪2
╙╘┘ ╪1
╙╘┴ ╪2
╙┬├ ╪1 ;╬OW.┴=DX
:├╧╬╘ ╙╘┴ ─╪
╠─╪ ╪1 ;╨UT.X1.INTO.╪,.NOW.WE.CAN.TRASH.╪1
├╧╠╒═╬ ╠─┴ ╪1 ;╞IND.THE.FIRST.COLUMN.FOR.╪
╠╙╥ ;(╘HIS.CAN.BE.MADE.MUCH.FASTER!)
╠╙╥ ;╘HERE.ARE.X1/8.128.BYTE.BLOCKS
╠╙╥ ;╫HICH.MEANS.X1/16.256.BYTE.BLOCKS
╠╙╥
┬├├ :┼╓┼╬ ;╫ITH.A.POSSIBLE.EXTRA.128.BYTE.BLOCK
╠─┘ #$80 ;IF.SO,.SET.THE.HIGH.BIT
╙╘┘ ┬╒╞╞┼╥
├╠├
:┼╓┼╬ ┴─├ ┬╒╞╞┼╥+1 ;┴DD.IN.THE.NUMBER.OF.256.BYTE.BLOCKS
╙╘┴ ┬╒╞╞┼╥+1 ;┴ND.STORE.IT!
╙┼├
╠─┴ ┘2 ;├ALCULATE.DY
╙┬├ ┘1
┬├╙ :├╧╬╘2 ;╔S.Y2>Y1?
╠─┴ ┘1 ;╧THERWISE.DY=Y1-Y2
╙┬├ ┘2
:├╧╬╘2 ╙╘┴ ─┘
├═╨ ─╪ ;╫HO'S.BIGGER:.DY.OR.DX?
┬├╙ ╙╘┼╨╔╬┘ ;╔F.DY,.WE.NEED.TO.TAKE.BIG.STEPS.IN.Y
╙╘┼╨╔╬╪ ╠─┘ ┘1 ;╪.IS.ALREADY.SET.TO.X1
╠─┴ ┬╔╘╨,╪ ;╨LOT.THE.FIRST.POINT
╧╥┴ (┬╒╞╞┼╥),┘
╙╘┴ (┬╒╞╞┼╥),┘
>>> ├╔╬╔╘,─╪ ;╔NITIALIZE.THE.COUNTER
├╨┘ ┘2
┬├╙ ╪─┼├┘ ;─O.WE.STEP.FORWARDS.OR.BACKWARDS.IN.┘?
╪╔╬├┘ >>> ╪╙╘┼╨,╔╬┘
╥╘╙
╪─┼├┘ >>> ╪╙╘┼╨,─┼┘
╥╘╙
╙╘┼╨╔╬┘ ╠─┘ ┘1 ;╫ELL,.A.LITTLE.REPETITION.NEVER.HURT.ANYONE
╠─┴ ┬╔╘╨,╪
╧╥┴ (┬╒╞╞┼╥),┘
╙╘┴ (┬╒╞╞┼╥),┘
>>> ├╔╬╔╘,─┘
├╨┘ ┘2
┬├╙ ┘─┼├┘
┘╔╬├┘ >>> ┘╙╘┼╨,╔╬┘
╥╘╙
┘─┼├┘ >>> ┘╙╘┼╨,─┼┘
╥╘╙
*-------------------------------
*.├LEAN.UP
├╠┼┴╬╒╨ ╠─┴ ╓═├╙┬ ;╙WITCH.CHAR.ROM.BACK.IN
┴╬─ #%11110101 ;DEFAULT
╙╘┴ ╓═├╙┬
╥╘╙ ;BYE!
*-------------------------------
*.╙OME.VARIABLES
╘╪1 ─╙ 1
╘┘1 ─╙ 1
╘╪2 ─╙ 1
╘┘2 ─╙ 1
╨1╪ ─╙ 1 ;╘HESE.ARE.TEMPORARY.STORAGE
╨1┘ ─╙ 1 ;╒SED.IN.PLOTTING.THE.PROJECTION
╨2╪ ─╙ 1
╨2┘ ─╙ 1 ;╘HEY.ARE.HERE.SO.THAT.WE
╨3╪ ─╙ 1 ;DON'T.HAVE.TO.RECALCULATE.THEM.
╨3┘ ─╙ 1
╨4╪ ─╙ 1 ;╘HEY.MAKE.LIFE.EASY.
╨4┘ ─╙ 1
╨5╪ ─╙ 1 ;╫HY.ARE.YOU.LOOKING.AT.ME.LIKE.THAT?
╨5┘ ─╙ 1 ;─ON'T.YOU.TRUST.ME?
╨6╪ ─╙ 1
╨6┘ ─╙ 1 ;╚AVING.ANOTHER.CHILD.WASN'T.MY.IDEA.
╨7╪ ─╙ 1
╨7┘ ─╙ 1
╨8╪ ─╙ 1
╨8┘ ─╙ 1
─╙╪ ─╙ 1 ;─╙╪.IS.THE.INCREMENT.FOR.ROTATING.AROUND.X
─╙┘ ─╙ 1 ;╙IMILAR.FOR.─╙┘,.─╙┌
─╙┌ ─╙ 1
╙╪ ─╙ 1 ;╘HESE.ARE.THE.ACTUAL.ANGLES.IN.X.Y.AND.Z
╙┘ ─╙ 1
╙┌ ─╙ 1
╘1 ─╙ 1 ;╘HESE.ARE.USED.IN.THE.ROTATION
╘2 ─╙ 1
╘3 ─╙ 1 ;╙EE.THE.ARTICLE.FOR.MORE.DETAILS
╘4 ─╙ 1
╘5 ─╙ 1
╘6 ─╙ 1
╘7 ─╙ 1
╘8 ─╙ 1
╘9 ─╙ 1
╘10 ─╙ 1
┴11 ─╙ 1 ;╘HESE.ARE.THE.ELEMENTS.OF.THE.ROTATION.MATRIX
┬12 ─╙ 1 ;╪┘┌
├13 ─╙ 1
─21 ─╙ 1 ;╘HE.NUMBER.DENOTES.(ROW,COLUMN)
┼22 ─╙ 1
╞23 ─╙ 1
╟31 ─╙ 1
╚32 ─╙ 1
╔33 ─╙ 1
╘┴ ─╙ 1 ;╘HESE.ARE.TEMPORARY.LOCATIONS
╘┬ ─╙ 1 ;FOR.USE.BY.THE.PROJECTION.ROUTINE
╘├ ─╙ 1
╘─ ─╙ 1
╘┼ ─╙ 1
╘╞ ─╙ 1
╘╟ ─╙ 1
╘╚ ─╙ 1
╘╔ ─╙ 1
*-------------------------------
*.╙ET.UP.BIT.TABLE
─╙ ^ ;├LEAR.TO.END.OF.PAGE
;╙O.THAT.TABLES.START.ON.A.PAGE.BOUNDARY
┬╔╘╨ ╠╒╨ 16 ;128.┼NTRIES.FOR.╪
─╞┬ %10000000
─╞┬ %01000000
─╞┬ %00100000
─╞┬ %00010000
─╞┬ %00001000
─╞┬ %00000100
─╞┬ %00000010
─╞┬ %00000001
--^
╙╔╬ ;╘ABLE.OF.SINES,.120.BYTES
├╧╙ ┼╤╒ ╙╔╬+128 ;╘ABLE.OF.COSINES
;┬OTH.OF.THESE.TRIG.TABLES.ARE
;CURRENTLY.SET.UP.FROM.┬┴╙╔├
┌─╔╓ ┼╤╒ ├╧╙+128 ;─IVISION.TABLE
╒╒ENCODED ┬INARIES
------------------
BEGIN 666 RUNME3D
═ 0@>" ╚ ┬╘&╥,*=!╠├$┌─╥)#54)%,╘0╬3╥(╠."╨┘ "╪(% "3(─┼.250╙1"(╠
═. !╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:
╞&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:
END
BEGIN 666 INIT3D
═ 0@─" ╚ ├╥!04─]'4─%-(%1/($┼.251)04╤)6─4@0╒5"13-$ $8(% "/(%-4
═15!(14╪@2┼5$1"╨@1╘5/4─=%(%1!64╤/4@!7"!─ ╞2(%5╘]22╘┼.1╥([ ',(
═'@!"4[(╓-3(╪.─)#╠├8╓-38┌0┼╩╥-├<╪- "#""@ 0;(╨.─1!╠╧^═-├ ╠╨@╥
═ (%)╠├"─,3(╨.┼,┼╠├,╥╦+\╚02╞╩+├4┌0╥6╥,╙*╠╧┬┴!*:╚╬-3╔!╠─&╩1$$
═╧0@╙ )─┬+┬([ -0(-╨"+(%,┼╠╙ @╔╥!3);(╥-3:╩4╥4 ┌╨@╪ (╠@0╥6╙,""╟
═($,┼╠├(╒-╩╔#)0 !"3╚ ┼╘)3╩──╠4╥4┌┼╘)#╩──╠0╥4 !╨─[ (( (0─\ $2╥
═.# ┌6├"╥,╙╔:╠╩╠╤,├@┌1%╩╥,0 ╬"48 @4╩╥,*0╥-34 . ┼' )─┬(2([ $╪)
═4 !1);(╓-*╤$╦2@╓-*╤:,*═:*0!─"5$ ┬╥!1);$╤,├<@╔╥!1);(╤,├< ? ┼2
═ (╠@426╙╩╙$╥-╥"╟(%$┼╠╩╠╤,├< ─╨┼3 (╠@426╙,""╟(%$┼╠├(╒-╩╔1)0"@
═"54 ┼╘):╩─╚╠424 ╦0┼: %╩╥6╩╔$6├╩" ,4)9 ">-# ┘-├╩9(─┘%050╠($┴5
═2#\┬ &┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:
1&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:
END
BEGIN 666 LISTME3D
═ 0@8" ╚ ├╥!.3╒1%4╥!&3╒(@0╒5"13-$ !╪("╨"/ $4(# "/(%1(15)%($%2
═12!35$┼,3"!!($9%5╥!-24┘/4┬!"54=3 &─(#0"/(%1(12!-3╒1)3╘╪@25,@
═2─522╒─@1─]2(%--04╤, (╘(#@"/($┼.0╒)%345.5%,┌(%!23╘)!0─╤9(%)/
═54┘$3╘9& ),(#╨"/ +@($ "/($9%14╨@1┼)%12!43╥!-3╘1)1┼─@5$┴%(%!!
═4─╒3+@#>"!$ ├╥!*55-4(%%5250@5$┴%(%!23╘=204╘@04┘$($╤)4╒0╬ ,)
═$@"/(%1262!#2$%.1╘┼.1╥!$($%.1"!:," ╚64]5($-!3@ ├"1, ├╥!%5─5.
═($╒!2╘4@6┬╒:,"!.14=!5$┼612─╬ $8)% "/($)%($-!4─5&54╨@04)/550@
═4─535$%25$┼.1╥$ ;0─5 (\@248@64]5(%=!3┼0@5$\@4╘5%(%┼/55(@0╘]-
═4%5415( ─@─6 (\@1$┼%($%.($%-05╔)3─<@1$5!5$@@2┼535"!465!% +@)
═%╨"/("=254╪@-├ ╟+┬!!3%=!65,@4┼5.(%1(12!%3┼1)4─4 ╤╨─8 (\@4%)/
═1╒)!32╪ ╙0─9 (\ \╨─: (\@4╘]-151)3453(%1(12!%6453($=%5"!#3╘┘&
═55-%1 8"┴╠ ├╥!!0─]55"!42$4@4$524╒!%0╒1)5─4╠($%.1"!42$4 .╨╚<
═ (\@0╒5"12!724╤,($╤/3╘╠@4─5!3$╤9(%=%25)$+@!?"┴╘ ├╥!*55-4($),
═24┘+($]2(%1262!43╥!&24┘$(%1(10"#"┴╪ ├╥!224=(5"!015)34$5#5$┼6
═12╪@($5615(@4╘5%3@"╚"┴\ ├╥!42$4@)╘-205╔9($-2051%)╙\@(%-!344@
═241%02╪ ╬@╚@ (\@4╘╤*(#<╧,3─╧.30 :&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:
═&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:&┴╚:
#&┴╚:
END
BEGIN 666 CUBE3D.O
═ !"╔ (╘@╘(╘┴╘*╘8╘"─/"1"-&-"@ *─?┴?╬╔$(7\3%41─╨41$1$@(" @(" @
═(" @(" @("!#54)%,╘0-#2 @(" @(" @(" @(" @(" @0┼─-╟╥ @("!35$50
═2$5.($╔51$29(" @($=%3╒)'12!405┼,3╒(-#9╠@($-(14-+($]55"!42$4@
═2┼5,62 ┘-"!)4╒-512!/1@╓6("!#/4┴!0╘═)3─>;($9/4┬!-3╒)%($1%5$%)
═3%,┴#0╘='9╪21├$╧1├*2("╘@24┘#+╘1%0╥!8+5)/5$%424].#1╘=$─8╙+╘8╘
═─┬ ═($┼.0╥]$14,@62╒23╒1!5$┼/3@╘='1)&-2]&-╔(@+2!)3─,╧1$5#(%╚═
═4─]4051)3╘╪-'1╘21├>2(%)%4╘544╨╘@(%!215-3(%$@5$\@455)5 ╘-!2 @
═(" @(%!215-3($%.62!+15─@5$\@0─5'24╪- +'[\ ╠@╘╧_(╘/;╞_$╤5$2#─
═_\─ \/╞╔─╥#2_┌┼ :0╥%^┌─%┴?╥╔ * ╚@ 8─?╧(:1"0^1┬┼^╓─╚┴?╬┼_&─
═┴?╥@ .┬*╪!#0┘*─ ┴:.╔,(6─┴0*═&- ╔\0─.├1├0╩0"-╙╤┬-╘!┬-╘1┬-╘┴┬-
═╘╤┬-╒!@@┘/_)┴= -╦<\8╥3╙╨8^[/&$╨╓$╠╞)╘ ╬═╙╤├╨5,[/&$╨╓$╠╞&╘ ╓═
═╘!├)//!#[═ 83#82╥8╦0"┌╫0&/ ╘╙═ 83#82╥8?0#:╫1&,─\\"/╬╘1┴,-┴+)
═┬] +╦=$8\!3.╘1┴,-┴+)┬- #3+$1╥5'0 ╘╥╥&!┬═╘┴┴═╙╤├)>) "┌7┬-╘┴@8
═╦=,8;= 8╥7┬0 ╬┼╪├=,8&*╫4&&╫1&,┼╪─ +╔>(╫4┬═╘╤├═╒!┬╨ ╞┼╪├=48
═&*╫3&&╫4&,┼╪─ +╔>(╫6&!┬═╘┴┴═╒!├)>) "┌7┬-╒╤@╪╦=(8[=08╠ )╔>(╫8
═&!┬═╘┴┴═╒┴├)>) "┌7┬-╓1@╪╦=(8[=48╠ )╔>(╫:&!┬═╘┴┴═╒1├)>) "┌7┬-
═╓╤@╪╦=88[=(8╠ )╔>(╫<┬═╘╤├═╘┴┬╨ ╞┼╪├=╘8&*╫2&&╫3&,┼╪─ +╔>(╫>
═&!┬╬╒1┬] !╩╬╒┴┴] !╩-╫╤┬╬╒1┬]@!─╪╦═88_8 9├> 8╦═,8╧8 9$ ╪82?]╔
═ 0╚82?]╔ 4╨╙$╨╩-╪1@╪╦═╨8╧0 :╦═╠8_0 :.*[9&/╘ &┴┬╬╓┴┴] !╚0#┴┴)
═_╓─!2┴┴)_╓─!3&(32┴┬╬╒╤┴]@!─╪╦═@8_8 9├>(8.*[9&+╓ &:[:&/╓ &3┬╬
═╓╤├]@!─╪╦═╨8_8 9$ ╪82?]╔ 4╚82?]╔ 4╥?$╘╚8╦═<8?0 :&*[8&'╘ &╚╫├
═&*[=&+╓ &3┬╬╫┴├]@!╞-┘!┬╬╓┴┬]@!─╪╦═╨8_8 9.*[;&/╓ &3┬╬╓1├]@!─0
═#┴┴)_╓─!2┴┴)_╓─!3.╨32┴┬╬╓!┴] !╚╪╦═<8_0 :├>48&*[:&+╘ &╩[;&'╘
═&├┬╬╓1├] !╚╪╦═╨8_0 :$ ╪82?]╔ 4╚82?]╔ 4╨╔%$╚8╦═<8?8 9&*[8&'╓
═&8╫╞&!┬╬╫1┬] !╩╬╫┴┴] !╩-┘╤┬═╫╤┬-┌!┬═╪!┬-┌1┬═╪1┬-┌┴┬═╪┴┬-┌╤┬═
═╪╤┬-[!┬═┘!┬-[1┬═┘1┬-[┴┬═┘┴┬-[╤┬═┘╤┬-\!@@╟1:╬╬╤┬╠╧!┬.╧╤┬,╨!@8
═╦> 82?]╔ 8╫╔&!┬═╪╤┴)_╓─!├>╨8&*╫╞&$╟_:0&-[╤@@╟1:╬╬╤┬╠╧!┬.╨1┬,
═╨┴@8╦=\82?]╔ 8╫╚&!┬═╪┴┴)_╓─!├>╠8&*╫┼&$╟_:0&-[┴@@╟1:╬╬╤┬╠╧!┬.
═╨╤┬,╤!┬═╪!┬-┌1┬═╪╤┬-[!┬═┘┴┬-[╤@@╟1:╬╬╤┬╠╧!┬.╤1┬,╤┴@8╦>$82?]╔
═ 8╫╩&!┬═┘!┴)_╓─!├>╘8&*╫╟&$╟_:0&-\!@@╟1:╬╬╤┬╠╧!┬.╙1┬,╙┴@8╦> 8
═2?]╔ 8╫╔&!┬═╪╤┴)_╓─!├>╨8&*╫╞&$╟_:0&-[╤@@╟1:╬╬╤┬╠╧!┬.╥╤┬,╙!┬═
═╫╤┬-┌!┬═╪┴┬-┌╤┬═┘1┬-[┴@@╟1:╬╬╤┬╠╧!┬.╥1┬,╥┴┬═╪!┬-┌1┬═╪╤┬-[!┬═
═┘┴┬-[╤@@╟1:╬╬╤┬╠╧!┬.╤╤┬,╥!┬╔ (6├╔0*%╔*─ ╚@┬@ )&├╥-#[┘╩3*╘/:┼
═╔*╓_&(╓[&*╫ &(╓\&*╫!&(╓]&*╫"&(╓^&"".%┌╫#&(╓[&*╫$&(╓\&"".%┌╫%
═&(╓]&*╫&&(╓^&"".%┌╓_&(╓[&*╫ &(╓\&"".%┌╫'&(╓]&*╫(&(╓^&"".%┌╫)
═&(╓[&*╫*&(╓\&"".%┌╫!&(╓]&*╫"&(╓^&"".%┌╫+&(╓]&*╫,&(╓^&"".%┌╫#
═&(╓[&*╫$&(╓\&"".%┌╫-&(╓[&*╫.&(╓\&"".%┌╫%&(╓]&*╫&&(╓^&"".%┌╫'
═&(╓]&*╫(&(╓^&"".%┌╘8╘$─"├1├0╩0┴% ╚4"3,41&*╫╬&&╫╧&!┴═\!@8:8"╩
═╧8 :┴?╥%_┴┬═┌!┴═┌1@8;>╚8┴?╠@┌!88╔?═╔0(╓[&!┬┼_╚7\╦>╠8;>╨8&&╫═
═&(7[(.@6&*7[:4"-╧!┴@&*7[1?╨╨-:7[$ ╒)_╓─!┴?╠8╔?╤)_╓─!╩0"@"4╔╞
═^┘ #&&7\┬-#╒2╞;[2╞;[2╞;[2╞;[2╞;[2╞;[┴?╒@╔?╠╨"┴┬┼_$╟_:0%,.!=)
═_╓─!┴?╬╔ * )2╞;[─ ,89?╥(╘/5*9╧═*9╧═*9╧═*9╧═*9╧═*9╧╬%_:7[$ ,@
═:1=)_╓─!┴?═@╚@"]>!?╨!╥#2_^┴,:╤=@#5-/34542$┼.1╥!#2$]+140@.┬@-
═ *╓[&(7[╦;╘8┴?╓═╧!┬%_*╓^&(7^╩0"%╚┌4"┴:0╪╔?╫┼^[ 2╔?┌─_(7\┴/┌┼
═^┌3]┴/╬%_>7[┴?╞╞^┌7[2─╔*2╔ %╚("$╚╤┴┼╔(6─.*7^┘?╥╨!*7\┘?┌%^╠7┘
═╠%┬─_+╘ &1&├─:.┼^4╔)_╓─!╤/┌╨(╬┴┼^╔ #╥.7┘2+╘ &1 *1:.%╚╙ "┘╩2╔
═@!&├─:-╚┘/╫0╫╓#╚9?╩0 ╪├┼^4┬] !─0"─6├┴:,╨ ╬:─╩8 1╚┘&├:.3]╘-]@
═╔/╥] !─1╚┘&├╔?╔*2?]╔ <3^╠"[(9?╞0&^├┼^─┬] !─0"─6├┴:,╨ ╬:─╩8 1
═╚┘&├:$╤^&$┬] !─1╚┘&├:,3^╘--@┬!┴┼^9 ;┌.7┌2+╘ &1 *1:.%╚╙ "┘╩2╔
═@!&├─:-╚3*╘82+╘ &1&├─:-╚╤/[0╘╞"═&- ╔]8╘8╘&
═
═ " 0" 0" 0" 8! (! (! (!@$ @$ @$ @& 0" 0" 0" 8!
═(! (! (!@$ @$ @$ @& 0" 0" 0" 8! (! (! (!@$ @$ @$ @& 0" 0" 0"
═ 8! (! (! (!@$ @$ @$ @& 0" 0" 0" 8! (! (! (!@$ @$ @$ @& 0" 0
═" 0" 0
═
╚
END
BEGIN 666 CUBE3D.S
═ ' ╩*┬╚╩*┬╚╩*┬╚╩*┬╚╩*┬╚╩*┬╚╩*┬╚╩*┬╚╩*┬╚╩*┬╚╩*@╘╩╚*"@╚*"@╚*"@
═╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@*@╘╩╚'-415!(14┌@:┼5$1*"@╚*"@╚*"@
═╚*"@╚*"@╚*"@*@╘╩╚&=%3╒)'1:!╘05┼,3╒*@╚*"@╚*"@╚*"@╚*"@╚*"@*@╘╩
═╚'-405)4140┌╚#<╧,3$╧.32@╚*"@╚*"@╚*"@╚*"@*@╘╩╚&9)3─┼32$5$.╩ ╫
═+╙$┘+╙─╘╚*"@╚*"@╚*"@╚*"@*@╘╩╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@
═╚*"@╚*"@*@╘╩╚'=%3$╨╠╚$┼&╚$%,3*!'3╘53╚%=%3$╥@5$┴)4┌"@*@╘╩╚%!2
═3╘=204╓@5╘┼,3*!23╒1!5$6@0:!#54)%+╩"@*@╘╩╚*"@╚*"@╚*"@╚*"@╚*"@
═╚*"@╚*"@╚*"@╚*"@╚*"@*@╘╩╚'1(25.@4%)/1╒)!3:!)4┌!)3┼1%3─1%1*!4
═3┌"@*@╘╩╚$%#0╘]-4$%.6:!42$6@05)424-,1:!)3╩"@╚*"@*@╘╩╚&,]:$%#
═2╘┼.1╥╥@:┼5,6: ┘-*!)4╒-512┌@╚*"@*@╘╩╚&9/4╩!$151!24╤3╚$].╚%1(
═25.@4%)/1╒)!32╥@*@╘╩╚%)%042@5$┴%╚$%25$┼#3$4┴╚*"@╚*"@╚*"@╚*"@
═*@╘╩╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@*@╘╩╚'=2251%╚%1/
═╚%53(:"@╚*"@╚*"@╚*"@╚*"@╚*"@*@╘╩╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@
═╚*"@╚*"@╚*"@*@╘╩╚%5.*$)%12┼-3┌"@╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@*@╘╩
═╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@*@╘╩╚%9)╚*"@╚*"@╚*"@
═╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@*@╘╩╚$╪╚24╪╔1┌"@╚*"@╚*"@╚*"@╚*"@╚*"@
═╚*"@╚*"@*@╘╩╚$%212┴42*"@╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@*@╘╩╚$4╔
═64]5*$^@╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@*@╘╩╚$┘,62╞@╚*"@╚*"@╚*"@
═╚*"@╚*"@╚*"@╚*"@╚*"@*@╘╩╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@
═╚*"@*@╘╩╚$%33"┴23╒-%*45%4*"@╚*"@╚*"@╚*"@╚*"@╚*"@*@╘╩╚*"@╚*"@
═╚*"@╚*"@╚*!%+─4╬0╒5-34┼.1╒.@╚*"@*@╘╩╚*"@╚*"@╚*"@╚*"@╚*"@╚*"@
═╚*"@╚*"@╚*"@╚*"@*@╘╩╚' ╬<╥┌@=$┴)4┌!705.@5╒))5%1%3╩!54╘┼.1┌"@
═*@╘╩╚*"@╚*"@;4523$┼.╚#$╥."┌@╚'=)5$┬@0:"@╚*"@*@╘╩╚*"@╚*"@3$┼4
═5$╤%╚$╒/1$┼&24-!5$┼/3╩!)5*"@*@╘╩╚*"@╚*"@5╘┼,3*!73╒)+╚$9)3─6@
═5╘┼42*"@╚*"@*@╘╩╚*"@╚*"@;4523$┼.╚#8╘+╩"@:4:@64]5╚*"@╚*"@*@╘╩
═╚*"@╚*"@1$].)╒2@2$%61:!%251(15(╬+┬┌@╚*"@*@╘╩╚*"@╚*"@5╘5,3"╥@
═5╘6@04╤,╚$┴!5─6@3╒52╚*"@*@╘╩╚*"@╚*"@3$┼45$╤%╚$9!54╤44╥┌@╚*"@
═╚*"@╚*"@*@╘╩*┬╚╩*┬╚╩*┬╚╩*┬╚╩*┬╚╩*┬╚╩*┬╚╩*┬╚╩*┬╚╩*┬╚╩*@╘-(&]╥
═9╥ ─,3 ╨, ╘-*╩!├3╘┘35$%.5%,-#6)╒9╞8╤(&5╤=2 ─,╙ ╨," [9─┼24╒2@
═0╘┴!4─%#5$52╚%-%5 ╒┬=69╞,┬!┼<74@)#,╪,# @.╫-%0╘].1*!#2$%204-4
═15*@4╘54#6)╒9╞9┼<┬!┼<74@)&$╙(#═╨4─5354╒!0─╤9╚%1(1:!405!%╚%=/
═3┬=4╚$)%╚%)53─┘)3─<->#$@97%╒("1╞8┬ [<$])3┼13╚$9/4╩!$4─%724┘'
═╚$&@3$┼.10╒┘,2!┼<74@)&9├(#═╘2$531:!:15)/╚%!!1╘6@041$4─534╘53
═#7@╥(&5╤=2 ─9╞0@.╘1/3┬=4╚$-/3─9,24-4╚%=)5$┬@8╞%╙:6,->3(@97%╒
═("1╞90╒─>"!┼<74@)&8┘#61┘(&5╤=2 ─9╞$-=&5═<#$@97%╒("1╞8┬ [;╘:@
═0╘]54┼-%+*!#3╒5,1*!#3╘┘&3$┼#5*!7251(╚%@╤#71┼;7 ╥(&5╤=2 ─9╞,@
═.╫1%35!/4─%26:!605))04),15,-86-├(&5╤=2 ─9╞(@.╫1(15-%╚$9/55*@
═5─%224%"3$53╚$%21:!54╘5$#6%╒>"!┼<74@)&9├(#═"6:!42$6@355,5$┼0
═3$┼#051)3╘┌@4─]55$┼.10╒┼>'0@97%╒("1╞9 ╒╥96╘@97%╒("1╞90╒┌=&5═
═<"!┼<74@)# ╥(#═╒4╘5$╚$9/4╩!"549&15*@4╒=!4"┌@╚&1/3┬=4╚%1/54-(
═+@╘-86┘╟;6%╪(&5╤=2 ╤,├ @.╫1(15)%╚$%21: ╥*┼!)+╘%.1╘╒!6*!!3─=,
═15,-;╓9╞<╓5╘(&5╤=2 ╓(#═╞3$]!5*!/1─93150┌╚%@]6$%#5%5!3"╚╥7─]&
═1┼-%5 ╘-*╩!╓:6,-#79═8╫-┬(&5╤=2 ─9# ╤. ╒┬:╓=╬9"!┼<74@)&0╨,├ -
═8╞]╥9&5╥(&5╤=2 ─9# ╥,0╒╙<╫1┴<╟0@97%╒(#$╙-#0@.╒)/5┌ ┘╚$┼.╚%-#
═4─5%3╩!-14╒/4┼╞@052@,3 ╥- ╘-#2╩@:╘523─%,#0╒├:')╧=70@97%╒("1╞
═9╞0╥#6=┼=&┼╬(&5╤=2 ─9╞9┼- ╘-*┬╚╩╚&╒!0╒)/4╨╘-;6]╓92!═86,-(&╤─
═82!=,0╘@<╫1┴(%╘╥#2 \/#╨-#6=┼=&═┼>2!═86,@(#═╫04┼4╚$9/4╩!!╚$═%
═65!215-3#7=┴:70@:╟-╥(&=┼=&┼╬#2!├;7 @(╙ ╨#2!┬97$@=╓%╔= ╘@/#╨\
═#0╒─96)╒9╥!═86,@(#═╨4─┼.5*!!╚$-(05)!0╒1%4@╓@(&1╧╚# @(#═─3╘╪╟
═5*!!4╒-%34),10╘-(&╤─82 ├73$-(&╔╙<┬!├:')╧=70-(#╪^/┬!╟971╦97─@
═.╓%.1*!704┼4╚%1/╚$-/3┼1)3┼5%#2!├;7 @(╥=3)╥ [;5╞@4╘5#4─5#5*!3
═5╘┼40╘┬@2╘59#2!┬;╞4@;#$-(&╔╙<┬!├;&5┴;╟5╨#2!╩;7 @9&]╬90╒╠,2!├
═;7 @(╥=8)╥ [;5╞@4╘5#4─54╚$%"3╒)4╚$═%60╘@8╞┘┼(&1╧;╞4-(&╔═<"!├
═;&5┴;╟5╨#2!╞:6╪-9&]╬92 \/#╨-#61┼8╟5╟82!═86,-(&1╧╚# -(&╤─82!=
═,0╘@<╫1┴(#$╨,├0-(&9╔;@╒─;╓┘┼82 \/#╨-#7-┼=&)╒9┬!═86,@(#═╨552@
═0┼5&1─524┌!72$521:!42$59╚$-!3╩!"1:!(55)4#2!╠9&$@(╙ ╨#2!╙=&$@
═8╟5╞9╞5╥#2!╠9&$@>╟1┼;7 @.╒╔414╒0╚$-/3┼1!24┘3╚%1(1:!(24=(╚$)9
═5$6@2$5210╘@<╫1┴(&)╒9╞9┼<┬╠╤#2 \/#╨-#2╚═+2╘═+2╘═+2╘═+2╘═+2╘═
═+2╘═+2╘═+2╘═+2╘═+2╘═#0╘@;&1┴(",─,# -('-╘82!┬:╓=╬9 ╘@<╫1┴(&)╧
═<╞1┼<@╘@;&1┴('9═8╫-┬#2!┴;╞0@(╥4╨,# ╨,3$╤,2 [<╘-2145.╚$╒%34]2
═6:!43┌ ╤,#(╘#2!╧<╞$@(╥4╨,# ╤,# ╨, ╘@<╫1┴('9═8╫-┬#0╘@;&1┘(",╨
═, ╘@;&1┴(",\='1┼>'0-('-╘82!╘96╒╨,0╘@;&1┴(",^='1┼>'0-('-╘82!╘
═96╒╨,@╘@:╞╒╨('1╔=&╤┼#71╘97┴╘(&┴┼>" ┘,╙ ╒,3$╤,3$╤(#═#3$5!4╩!3
═0╒)%14╪╠╚%=(251%+*!#4┼-2╚$1.#2!╘>'0@)┌"@╚*"@╚*"@╚*"@╚*"@╚$-5
═0─4╙1"<╠,$0╠,$0-('1╪=" ╟╚*"@╚*"@╚*"@╚*"@╚*"@╚*!"62<╠,$0-(&┴┼
═>" ┘9┬ [0╒┼!3@╘@='┴╘(">@╚*"@4╒1%4$┴%3╩!*541$)╨╘@:&5╪(#─┘#2!╘
═>'0@)┌"@╚*!'14]21╘6@5$%93$]2)╥╨╨1"╨╨1 ╘@:&5╪(#┼┬#2!╘>'0@)┌"@
═0╘┴%0╘╬@3╒54╚%1(1:!*54╤9╚#─╘╚$┼34╒5%╚$]&)╥╨╨1 ╘@:&5╪(#─╓#2!╘
═>'0@)┌"@0╙╒(04-+24┘')╨╘@:&5╪(#┼┬#2!╘>'0@)┌!&3╒*@34]21:!$151!
═24╤3(2<╠,$0-(&┴┼>" ╨9#%─,60┘93$╥#2!╘>'0@)╘8╤+╘8╥)╥╨┘,@╘@='┴╘
═(">@+:!)3─,╧1$5#╚%@═4─]4051)3╘╪╟+#!$#2!╚97@@,60╤9#$╥#2!╘>'0@
═)╘8╙+╘8╘)╥╨┘,@╘@='┴╘(">@+:!)3─,╧1$5#╚%─═4─]4051)3╘╪╟+#!$#2!╚
═97@@,60╤9#$╥#2!╘>'0@)╘8╒+╘8╓)╥╨┘,@╘@='┴╘(">@+:!)3─,╧1$5#╚%╚═
═4─]4051)3╘╪╟+#!$#2!╚97@@,60╤9#$╥#2!╘>'0@)╘8╫)╥╨┘,@╘@='┴╘(">@
═4─531513)╥╨╨1 ╘@='┴╘(">@╚%!215-3╚%&@5$^@455)5"<╠,$0-(&┴┼>" ╨
═9# ╒#2!╘>'0@)┌"@╚*"@╚%!215-3╚$%.6:!+15╞@5$^@0─5'24╪╟+#!$#2!╚
═97@@,# -=&┼╘;&4@;&1┴("┴╘96╒╨,2─╠>0╘@8╞5╤(#╔├;╓┘╘#2!╩<╫(@8╓┴╥
═;╫5╘#2!╔;╟─-(&)╬92!╘:71╠90╘@:6┘├('1┼;7 ╥#2!╩;7 @=&┼╘;&4-.╞-╧
═;╟0@/├╪^(&=┼=&═┼>0╘-*┬╚╩*╩!╙152@55"@5$%"3$53*#\╔#0╘╩╚'1!0─╤%
═4┌!!4─6@0╒524─5.5$╤9╚%-%5*!54*!)3╩!┬87-╔8╨╘╩╚$%.1*!"6:!42$6@
═05-314╒"3$52+@╘-=&%┬;&5╙#0╘╩*┬╚╩╚&-,14%2╚%-#4─5%3╩!!3─2@4╘54
═╚%50╚")"251-05 ┬#0╒╙971╒<"!╠9&$@(╙$╘-╨╘@:╟-╥(&-╚<╞]╒= ╘@;&1┴
═(",\<╫-╘87)╘#2!┴9&,@(╙$╥(#═╘2$6@1╘]!3*!)4┌!43┌!#14┘415*@5$┴%
═╚$=205!(24-3#2!╙=&$@=&5═<#$@.╓-/3%5-3╩ ╤,@╘@;&1┴(",^<╫-╘87)╘
═(#═╥3╒>@.0╘@<╫1┴('1┼;7 ╤*╙$@.╫-╙=&%╥=*!03╘┼.5%.@5$^@4─]7╚#─-
═(&╤─82 ├,# -(&╤─>2 ├,# -(&╤─>" ├,# @.╒┬@5╘┼,3*!#3╒5.5* ╤-╩!2
═3╒=3╚$9/4╩!54╨╘@8╓╤├#0╘┌;&]╧<"!╙=&$@*'1┼;7 ╤*2╤┘#2!╔;╟─-(&%─
═8╥ ├,38-(&)├8╥ ┌;&]╧< ╘@8╓╤├#2!╠9&$@=&5═<#$-(&%─8╥ ├-# @.╓┘%
═142@5$^@041$╚#0╨╚%1/╚%1(1:!"05-%╚%!/24┘415(-('-╘82!╘96╒╨,2 [
═=$^@2┼5-4*!43┌!42$6@3─585*!23╒<-(&╤─82!╘96╒╨,2╠╤#2!┴9&,@(╙ ╨
═(#═╘04═%╚$-!4─6@3╘:@0╘%24─┼%4╨╘@<╫1┴('1┼;7 ╤*╙$-(&╤─>2 ├,# -
═(&┼╬> ╘@='┴┴(" [>*!)4┌!!3%-/╚$%.╚$┼.1$58╚$┼.5$^@5$┴%╚$-(05)!
═0╒1%4╩!.54╒"15(-(&-╨>" ├,38-(&)╬92 ┌;&]╧<" [;─5%1*!43┌!$3┌!)
═5* ╤-╩!424╒%4╨╘-(#╪^/┬!─96)╒9╥╨╟,┬<-*┬╚╩*╩!╙152@55"@0┼5&1─52
═4╨╘-(&╤─82 ├/&)╒9╞8╤#2!╙=&$@8╟5╞9╞5╥#2!╠9&$@(╙┘┬=69╞,0╘@<╫1┴
═(&)╒9╞9┼<┬╠╤#2!╙=&$@>╟1┼;7 @.╒╔414╒0╚%=)3$╥@34%+1:!,249%╚%-)
═35!,1:!&3╒*@55,-(&╤─82!╓;6-╙8@╘@86┘─(",┼,3$╤,3 ╨,#$@.╫-405)4
═╚$┴%4─6@4╘^@5$┴!5*!35╘%0╚$)51─9%4┼.@5╘┼,3*!73╒)+╚%))1╘┴4#2!╧
═<╞$@(╥4╨,# ╨,3$╤, ╘@<╫1┴('9═8╫-┬#0╘-*┬╚╩*╩!╙152@55"@24┘)5$┼!
═3*!604╤515,-#6┼╬:70@;&1┴(",╨, ╘@<╫1┴(&1╙> ╘@<╫1┴(&1╙>0╘@<╫1┴
═(&1╙>@╘@<╫1┴('-╪#2!╙=&$@<╫─-('-╘82!╙>@╘-(#╪^/┬!─96)╒9╥╨╟-"<-
═#2╚═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═#2╩@;4%)3╩!,3╘]0
═#0╘╩*┬╚╩╚&=%5*!+15┼04─534╨╘-;6%╔;@╒╦<')┼<╫,@:╟-╥(&=┼=&┼╬#2!├
═;7 @(╙$╙,╥ [9├$_#2!┬;╞4@.╞8╥#2!╠9&$@9'-╪#2!├;7 @(╓%╬9╓╒┴>"\╥
═(#═╬3┌!-3╒)%╚%1(04┌@4$─-(&)┼<2 ┌8╓]╬= ╘@:6┘├(&1╙>" [3╒1(15)7
═25-%╚$┼.0╒)%05-%╚%@═4─]4051)3╘╪-(&╔═<" ┌8╓]╬= ╘┌9├(@8╓╒╨(",╤
═,╙<@.╓8╥/╨╘@8╞┘┼(#╔╞,╨╘@;&1┴(&1╙> ╘@8╞5╤(#╔├;╓┘╘#2!─96,@9'-╪
═#2!╩;7 @.╞-╧;╟0-.╞8╙(&-═<" ├,3,╘#2!┬;╞4@.╞8╘#2!╠9&$@9'-┘#2!├
═;7 @(╓%╬9╓╒┴>"\╥#2!┬97$@.╞-╧;╟0-(&┼╬8╥!─<╫─@.╓┼.0╒)%05-%╚%─═
═4─]4051)3╘╪-(&╔═<" ┌8╓]╬= ╘┌9├0@8╓╒╨(",╤,╙@-(&)╬92 ┌9├4-(&╤─
═82!─<╫─-(&)┼<2 ┌8╓]╬= ╘@9&5├(&1╙>0╘@:╞╒╨(#╔├;╓┘╘#3╔╞-2!├;7 @
═(╙$╙-0╘@8╞┘┼(#╔╞-@╘@;&1┴(&1╙>@╘@8╓╒╨("-┴;╞=═87@╧,@╘@8╞5╤(#╔├
═;╓┘╘#2!╔;╞,@9'-┌(#═:+5)/5$%424].#2!╩;7 @.╞-╧;╟0-.╞8╓(&-═<" ├
═,3,┘#2!┬;╞4@.╞8╫#2!╠9&$@9'-┌#2!┬97$@.╞-╧;╟0-(&1┼8╥!─<╫╚-(&╔═
═<" ┌8╓]╬= ╘┌9├<@8╓╒╨(",╤,╙8-(&)╬92 ┌<0╘@:╞╒╨(&┼╬:70-.╟$@8╓╒╨
═(",╟42<@.╒&@455)5%,-(&)╬92 ┌8╓]╬= ╘@:╞╒╨(&-╠96%╬=7 -#3╔├;╓┘╘
═#2╩@/├╪^╚&1┼8╟5╟+"<╒)╨╘-*┬╚╩*╩!╒4$1!5$6@04┘'3$53#0╒╒<&1┴=&4@
═8╓╤├#2!╠9&$@<╫@-(&%─8╥!─<╫@-(&-═<" ├86┘╟;6%╪(#═┴4─6@5╘6@/├╓@
═34%824╒53:!!3─=,13\-(&)├8╥ ┌8╓]╬=#$-('-┬8╥ ├86┘╟;6%╪(#╔╔1┬!3
═3╥╨@4─53150-.╞-╧;╟0╤('-╘82!╙> ╘@8╓╤├#2!╠9&$@<╫─-(&%─8╥!─<╫─-
═(&-═<" ├86┘╟;6%╪#2!┬8╓,@.╞-╧;╟0╥#2!╙8╞,@(╓%╬9╓╒┴>" [<╘%-1:!$
═14%,#3╔├;╓┘╘,┬!╙=&$@<╫─-(&-╠8╨╘@;&1┴('-┌#2!┴9&,@9'-┌#2!├;7 @
═(╓%╬9╓╒┴> ╘@8╞-├(#╔├;╓┘╘,╨╘@<╓)├("-┴;╞=═87@-.╞-╧;╟0╙('-╘82!╙
═>@╘-#2╚╩*┬╩@<─]4051%╚$-/3╒)$24┘!5$53#0╒╥;╫1┴=&4-#2╚╩*╩!╞25)3
═5"╥@0╘%,0╒5,051%╚%0╤+%0╥+"╪╬+┬╤4,3 -#2╚╩╚'173┌!-04-23╒.@5$^@
═4╘┼-4$╤)1┼╞@3╒52╚$╤)1─4-861─82!═86,@(#═┴1$2@5%=/╚$%.1╘╤%4┌!4
═3╘=%5$┴%4@╘@8╓╤├#2!╠9&$@73$-(&%─8╥!=,@╘@8╓╒╨("-┴;╞=═87@@.╓┼3
═╚%1(1:!354╓@/╩ ╥*┼!)/╨╘@8╞-├(&1╧;╞4-('-┬8╥ ├86┘╟;6%╪(#═╔1╩!3
═3╥╥@4╒5"5%)!0╒2@,┬╔020╒─;╓┘┼(#╨\/ ╘-<╫5┬82!═86,@(#═╙54)44─%#
═5*!45╘^@04┘'3$53#2!╙96,-(&╤─82!=,0╘@<╓)├(%╘╥#2!┬8╫,@9&]╬90╘@
═861├("-┴;╞=═87@@.╓]/4%,╠╚%=%╚$┘%142@5$^@041$╚#(╩4$─-9&]╬92 \
═/#╨-#2╚╩╚&┘/5┌!#04╤#54╤!5$6@5#$╠5#(╠151#+@╘-(#╪^/┬!╙=6)┴+'-┘
═.╫-┌#2!╙=&$@=#$@.╒0╤/5-9+5-:#2 ^/├╪@861─82╤╙>3═╙>@╘@<╫1┴('0╥
═(#═4,├╒362═36@╘@/├╪^(&%─9&$╠<╫@[<╫╚-('-╘82!╘,╥ [5#,]4╒@╦4╒╚-
═(#╪^/┬!╙=6)┴+'-╪.╫-┌#2!╙=&$@=#0@.╒0╘/5-8+5-:#2 ^/├╪@861─82╤╙
═>#═╘,@╘@<╫1┴('0╒(#═4-3╒36"═4,@╘@/├╪^('-╒8╞$╠<╫@[=#$-('-╘82!╘
═-┬ [5#8]4╒@═5#$-(#╪^/┬!┴9&1┴+'-╪.╫0╤#2!╙=&$@=#<@.╒0╫/5-8*╒0╤
═#2 ^/├╪@<╫5┬82╤╘,├═╙> ╘@<╫1┴('0╪(#═4.#╒4,┬╒36 ╘@/├╪^('-╒8╞$╠
═<╫─[<╫@-('-╘82!╘.2 [5#─]4╒─═4╒@-(#╪^/┬!┴9&1┴+'-╪.╫-┘#2!╙=&$@
═=#$╨(#═4,3 ]4╒@╦4╒─-#2╩@952@5─])3$$┴#0╘╩*┬╩@;─585"╥@0╘%,0╒5,
═051%╚&$╠8┬╤├+"╪╬+┬╤╔#0╘╩*╩!┴3─]42$52╚%5314953*!,25143$6@34%#
═4─\-9&┼╓,┬!═86,@(#═─259)1$6@0:!324=.142@3┼5-0─52╚$)9╚#(-.╓┼4
═╚$┼3╚$%34╒5-142@5$┴!5*!42$6@3┼5-0─52#2!┬<&╨@<&]╙(#═)4┌!)3╩!4
═2$6@04-#54╒53$%43╒(-(&-╠8╨╘@96]╥(",─9╞8@.╫=%╚$┘%142@5$^@54╪═
═3─5'051)5─6@5$┴%╚$┘534)%4@╘@861├(",╨,2 [0┼╞@5$%+24┘'╚$┼4)╒.@
═0╘]-4$╤%345.5 ╘@;'-╥(" [1$┼6241%╚$)9╚%173╨╘@8╓╤├#2!┼;╫(@(╥1╞
═9@╘@861├(",╨,2 [;4%+1:!)5*!.14=!5$┼61:!!1╘%)3@╘@:╞╒╨(&1╧;╞5─
═:78-<&]╙(&╤╙<┬ @.╓┘534)%4╩!)4┌!03╒-)5$┼610╒─;╓┘┼9&┼╓(#╨\/ ╘-
═;75╠,┬!═86,@(#══54╤425!,6:!!╚%-)1╘┘%1*!.54╒"15*@0┼╞@,@╘@8╟!╠
═('!╧<╓╘-(&-╠8╨╘@96]╥(",─9╞8-(&%─8╥ ├)# ╤#2!┴<╓╨-(&-╠8╨╘@96]╥
═(",─9╞8-(&%─8╥ ├)# ╤#2!╩;7 @9&]╬96╒╒; ╒╨;╫-═(&%╙; ╒─;╓┘┼;75╠
═(#╨\/ ╘-*┬╩@;─]41:!42$%4╚%=%╚$%21:!#55)214┘43%╞@34%+24┘'╚$&@
═34┼.3╒*@3$5!4 ╘╩*╩!/1╩!&04┼42*!42$%4╚$┘/╚$]615)&3$]74┌!724╤,
═╚$]#0╒52+@╘-.╞-┴;&-┴(&-╠8╨╘@;&1╪('0╤#2!╠9&$@8╓]╙+'@-(&╤─>"!╘
═,@╘@861├(&-╧<╥╤╪#2!╙=&$@83$╤(#═┴/2┴#3╒,╚5#$╔*╘-/4╥┴4,┬─╔+╙(-
═.╞-┴;&-┬(&╤─>"!╘,0╘@;&1┴('-╔;┬╤╪#2!╙96,-(&╤─>"!╘,@╘@<╓)├('-╔
═;┬╤╪#2!╙=&$@8├$╥(#═┬/2┴324╪╚5#$╔+5-)3┬┴4,┬─╔+╙(-.╞-┴;&-├(&╤─
═>"!╙>0╘@;&1┴('-╔;┬╤╪#2 ^/├╪@;75╠,@╘@<╫1┴(&,╤,╥ [8╙╒324╪╚4╒─╔
═#3╔├86╤├9"!╙96,-(&╤─>"!╘. ╘@;&1┴(&-╧<╥╤╪#2!╠9'@@=#<-('-┬8╥!├
═;╫,╠> ╘@<╓5├#2!╠9'@@=#4-('-┬8╥!├;╫,╠> ╘@8╓╤├#2!╠9'@@=#8-(&%─
═8╥!├;╫,╠>" [9$─]*$-/4╥┴4."─═0╘]3*%0╫*2═#3╒,╚5#8╔+4-/4╥┴4-2─╔
═+╙(-(#╪^/┬!─:78╥#2!├;&,-(&╤─>"!╘,╨╘@861├('-╔;┬╤╪#2!╙96,-(&╤─
═>"!╘- ╘@<╓)├('-╔;┬╤╪#2!╙=&$@9#(╤(#═─/2┴324╪╚5#,╔+5-)3┬┴4-"─╦
═9$─╔+╙(-.╞-┴;&-┼('-┼8╨╘@;&1╪('0╒#2!╠9&$@<╓┼╬+'@-(&╤─>"!╘-@╘@
═<╓)├('-╔;┬╤╪#2!╙96,-(&╤─>"!╘-╨╘@<╓)├('-╔;┬╤╪#2!╙96,-(&╤─>"!╘
═. ╘@<╓)├('-╔;┬╤╪(#═┼23╘╚4╘┼.*%0╒*2╒324╪╚5#8╔+5-)3┬┴4-╥─═4╘┼.
═*%0╪*2─╧,@╘@/├╪^(&1╔=├(-(&-╠8╨╘@;&1╪('0╙#2!┴9&,@8╓]╙+'@-(&-╠
═8╨╘@;&1╪('0╘#2!┴9&,@8╓]╙+'@-('-╘82!┼,├(@.╓4]*$-/4╥┴4,╥─╦0╘]3
═*%0╘*2═┼22─╧,@╘┌8╓%╠8╓8@;&1╪('0┘#2!╠9&$@<╓┼╬+'@-('-┼8╨╘@;&1╪
═('0╤, ╘@<╓)├('-╔;┬╤╪#2!╙=&$@9├(╙(#═╞/2┴324╪╚5#─╔+5-)3┬┴4,3 ╔
═*2\╥#3╔├86╤├9╥!╠9'@@=#8-(&╤─82!╙:6╪╠> ╘@<╓5├#2!╠9'@@=#@-('-┬
═8╥!╙:6╪╠> ╘@<╓5├#2!╠9'@@=#<-('-┬8╥!╙:6╪╠> ╘@<╓5├#2!╠9'@@=#4-
═('-┬8╥!╙:6╪╠>" [9╘─]*%-)3┬┴4-┬─═4╘┼.*%0╪*2╒324╪╚5#<╔+5-)3┬┴4
═-2─╔+╙(-(#╪^/┬!─:78╥#2!├;&,-(&╤─>"!╘- ╘@861├(&-╧<╥╤╪#2!╙96,-
═(&╤─>"!╘,╨╘@<╓)├(&-╧<╥╤╪#2!╙=&$@9╙,╤(#═╟/2┴#3╒,╚5#0╔+4-/4╥┴4
═,╥─╦9╘─╔+╙(-(#╪^/┬!─96)╒9╓$╠9╙,╤#2 ^/├╪@9&5┬=6<╠)╘<╟#3╔├86╤├
═:"!├;&,-(&╤─>"!╘-@╘@;&1┴(&-╧<╥╤╪#2!╠9'@@=#<-(&%─8╥!├;╫,╠> ╘@
═<╓5├#2!╠9'@@=#4-('-┬8╥!├;╫,╠> ╘@<╓5├#2!╠9'@@=#@-('-┬8╥!├;╫,╠
═>" [:$─]*$-/4╥┴4-┬─╦0╘]3*%0╫*2╒#3╒,╚5#4╔+4-/4╥┴4."─╔+╙(-(#╪^
═/┬!─:78╥#2!├;&,-(&╤─>"!╘,╨╘@861├('-╔;┬╤╪#2!├;&,-(&╤─>"!╘- ╘@
═861├('-╔;┬╤╪#2!╙=&$@:#,╥(#═╚/2┴324╪╚5#,╔*╒-)3┬┴4-"─╦:$─╔+╙(-
═.╟=╚97<@8╓╤├#2!╠9'@@=#─-(&╤─82!├;╫,╠> ╘@;&1╪('0╤, ╘@861├(&-╧
═<╥╤╪#2!╙=&$@:3,╙(#═╔/2┴#3╒,╚5#─╔*╘-/4╥┴4,3 ╔*2\╥#0╘╩*╩!╔5"=3
═╚$%,3*!$3╒=.2$┼,3*!&4─]-╚$┴%4─4╬#0╘╩*╩!╥3╒1!5$4╠╚%!23╘╔%0╒0╠
═╚$%.1*!35$]21:!42$6@4$])3┼13#61╧=╓┘╚:6╤╠(&╤─82!┴,3$@.╫1(25.@
═25.@1╘545$┼.1┌!43┌!"1:!!╚%)%04╥@34534╨╘@<╫1┴('1┴#2!╠9&$@8├$╥
═(#═╘2$6@4─5!4╘].╚%1(25.@25.@1$].10╘@<╫1┴('1┬(#═)4┌!43┌!-04═%
═╚%1(1:!#3╘1%╚$&@3$┼45$╤%#2!╠9&$@8╙$╙(#═%05-)15*@5$^@4─5!1* ╚
═04┘$╚$1%0┼5'(2─-('-╘82!╘8╨╘@;&1┴(&0╥,2 [=$┴%4╘6@05)%╚$%,3*!4
═14╒03╒)!4┼╞@3$]#051)3╘┘3#2!╙=&$@=&0@.╫53142@0┼╞@5$┴%╚%!23╘╔%
═0╒1)3╘┌@4╒5"4─]55$┼.12╪-(&╤─82!┼,├(-('-╘82!╘92 [;╒1(15)725-%
═+*!42$521:!73╒5,1*!"1:!%24=(5 ╘@;&1┴(&8╥,╥ [3$].1┌!23╒5424┘%
═4┌!(15)%+@╘@<╫1┴('1╞#2!╠9&$@9╙,╤(#═┬552@252@5╘]53$2@0─6@4╘┼'
═3─┼&24-!3┼1,6:!&05-415(-('-╘82!╘9╨╘@;&1┴(&@╙,@╘@<╫1┴('1╚#2!╠
═9&$@:3,╙#2!╙=&$@=&─-#2╩@8:!.14%4╚$╒!0╒)/#6┘┼9╥!═86,@(#═├2$%.
═1╘6@5$┴%╚%-)1╘┌@3╘:@0:!45╘\╟4┌!#3╘╒03$5-14┘4#2!├;&,-(&╤─82!=
═,2 [3┼5-0─52+@╘@96]╥(",─9╞8-(&%─8╥ ├)# ╤#2 \/#╨-#2╩@<#$]6╙&@
═,: ╤70╘@:╟-╥('!╥;╓╔┼8╫0@.╫5.4─],3*!42$┼3╚%=(3╘╤%╚%1(24┘'#2!╠
═9'@@='@╤(#╠╚4╘]24┼╞@04)/552@5$┴%4╘6@5%=/╚$╤)3─53*0╘@;&1┘('1┘
═,2 [*%-%1:!╨<╞]╩96-╘╚$9/4╩!214%33╘┌@5╘┴9*0╘@<╫1╪(' ╤>" [9─]2
═╚$&@4%)%5%19╚$))1┌!34$5%1*!)3─-214%312$-('-╘>2!╨,7─-*╩!╨,├╒;
═,: ═,: ╤70╘@/├╪^(&┘┼9╥╤┬,3(@.╓-(04┘'1:!42$531:!%3$5-14┘44╨╘@
═<╫1┴('1┬#2 ^/├╪@;╞5╟+&4╥,┬ [<╘┼.0╘6@6:!)4┌!.3╒>@+3$-('-╘82!╘
═90╘@/├╪^(&┘┼9╥╤╚,╙(-('-╘82!╘: ╘@:╟-╥('!╥;╓╔┼8╫0-(&╤─>"!╘>#$-
═(&╤─>2!╘>3$-('-╘>"!╨,╟@-('-╘>2!╨,╟─-*╩!╨,╙╒;+3&@+3&@,5╘-(#╪^
═/┬!╬96<╠83$╤#2!╙=&$@=&$-(#╪^/┬!╬96<╠9#(╤#2!╙=&$@=&0-(#╪^/┬!╬
═96<╠9╙,╤#2!╙=&$@=&<-(&╔╙<┬!╨<╞]╩96-╘#2!╠9'@@='@╤#2!╠9'─@='─╤
═#2!╙='@@<#-╪#2!╙='─@<#-┘#2╩@<#0]6╥╘╤╚#&@,5╘-(&╤─82!┬,3(-('-╘
═82!╘8@╘@;&1┴(&4╥,@╘@<╫1┴('1┼#2!╠9&$@:#,╥#2!╙=&$@=&@-(&╔╙<┬!╨
═<╞]╩96-╘#2!╠9'@@='@╤#2!╠9'─@='─╤#2!╙='@@<#1╪#2!╙='─@<#1┘#2╩@
═<#@]6╥╘╤╚#&@+3%=#2 ^/├╪@;╞5╟+&,╤,╨╘@<╫1┴('1├#2 ^/├╪@;╞5╟+&8╥
═,╨╘@<╫1┴('1╞#2 ^/├╪@;╞5╟+&─╙,╨╘@<╫1┴('1╔#2!╩<╫(@<')╧:╞5├= ╘@
═;&1╪('1╪,0╘@;&1┘('1┘,0╘@<╫1╪(' ╪> ╘@<╫1┘(' ╪>0╘╩╚' ╫/5╠═,: ═
═,: ═,5╘-(#╪^/┬!╬96<╠8├$╥#2!╙=&$@=&(-(#╪^/┬!╬96<╠93(╥#2!╙=&$@
═=&4-(#╪^/┬!╬96<╠:#,╥#2!╙=&$@=&@-(&╔╙<┬!╨<╞]╩96-╘#2!╠9'@@='@╤
═#2!╠9'─@='─╤#2!╙='@@<#=╪#2!╙='─@<#=┘#2╩@<#8]6╙&@+3&@+3%=#2!╠
═9&$@83$╤#2!╙=&$@=&$-(&╤─82!─,├$-('-╘82!╘9 ╘@;&1┴(&<╙,0╘@<╫1┴
═('1╟#2!╩<╫(@<')╧:╞5├= ╘@;&1╪('1╪,0╘@;&1┘('1┘,0╘@<╫1╪(' ╓> ╘@
═<╫1┘(' ╓>0╘╩╚' ╒/5╠╤╚#&@+3%=#2!╠9&$@8├$╥#2!╙=&$@=&(-(&╤─82!┼
═,├(-('-╘82!╘90╘@;&1┴(&@╙,@╘@<╫1┴('1╚#2!╩<╫(@<')╧:╞5├= ╘@;&1╪
═('1╪,0╘@;&1┘('1┘,0╘@<╫1╪(' ╒> ╘@<╫1┘(' ╒>0╘-*┬╚╩*╩!├3$5!4╩!"
═549&15(-#2 ^/├╪@<╓5╘8╟5╞#6-╠<╞)╒9┬!╠9&$@(╥0╨," [<%)%5%19╚%-4
═4─%)1╘┴41─]25╘%21"╨-(&╤─>" ├)# ╪(#═╔╚%1(24┘+#2!╠9'─@(╥0╨, ╘┌
═;&]╧<"!╙=&$@*&)╒9╞9┼<┬─╠>0╘@:6┘┘#2!┬;╞4@.╞╤╧;╫ -(&┼╬8╥!┬=69╞
═97(╦,0╘@9&5╪#2!┬;╞4@.╞╤╧;╫ -(&╤─82!┬=69╞97(╦,0╘-*┬╚╩*╩!╞24┘!
═3$╤9+*!$4─%7╚%1(1:!,24┘%4╥╪-#2!╠9&$@<#%╪(#═;,: ╤╚#%=#2!╙=&$@
═='@╤#2!╠9&$@<#%┘#2!╙=&$@='─╤#2!╠9&$@<#)╪(#═;,: ═,: ╤70╘@<╫1┴
═('1╪,@╘@;&1┴(' ╥>0╘@<╫1┴('1┘,@╘@:╟-╥(&1╥87<@.╓9)4┼-4╚$╤)3─4-
═#2!╠9&$@<#-╪(#═;+3&@+3&@,5╘-('-╘82!╘>#$-(&╤─82!╨,╫─-('-╘82!╘
═>3$-(&╔╙<┬!─<╞%╫(#═╙14-/3─2@3$┼.10╘-(&╤─82!╨-'@@.╒╠═,: ╤╚#%=
═#2!╙=&$@='@╥#2!╠9&$@<#1┘#2!╙=&$@='─╥#2!╩<╫(@9')┴=╥ [=$┴)4─2@
═3$┼.10╘-(&╤─82!╨,7@@.╒╠╤╚#&@,5╘-('-╘82!╘>#$-(&╤─82!╨,7─-('-╘
═82!╘>3$-(&╔╙<┬!─<╞%╫(#═╞3╒525$┬@3$┼.12┌@╚&].1:!&04-%╚$1/3─4╬
═#0╘@;&1┴(' ╒>" [6╙&@,: ═,5╘-('-╘82!╘>#(-(&╤─82!╨-7─-('-╘82!╘
═>3(-(&╔╙<┬!─<╞%╫(#═╞259%#0╘@;&1┴(' ╓>" [6╙&@+3&@+3%=#2!╙=&$@
═='@╤#2!╠9&$@<#9┘#2!╙=&$@='─╤#2!╩<╫(@9')┴=╥ [<╘┼8#0╘@;&1┴(' ╥
═>" [6╙&@+3&@,5╘-('-╘82!╘>#(-(&╤─82!╨,╟─-('-╘82!╘>3(-(&╔╙<┬!─
═<╞%╫(#═╙159%3@╘-(&╤─82!╨-╫@@.╒╠═,: ═,: ═,5╘-('-╘82!╘>#(-(&╤─
═82!╨-╫─-('-╘82!╘>3(-(&╔╙<┬!─<╞%╫(#═┼24=(5 ╘-(&╤─82!╨,╫@@.╒╠═
═,: ═,: ╤70╘@<╫1┴('1╪,0╘@;&1┴(' ╙>0╘@<╫1┴('1┘,0╘@:╟-╥(&1╥87<@
═.╓┘)3─4-#2!╠9&$@<#┴╪(#═;+3&@,: ═,5╘-('-╘82!╘>#$-(&╤─82!╨.'─-
═('-╘82!╘>3$-(&╔╙<┬!─<╞%╫(#═╘14╪-#2!╠9&$@<#1╪(#═;+3&@,: ╤70╘@
═<╫1┴('1╪,@╘@;&1┴(' ╘>0╘@<╫1┴('1┘,@╘@:╟-╥(&1╥87<@.╓5,159%3@╘-
═(&╤─82!╨-7@@.╒╠╤╚#&@+3%=#2!╙=&$@='@╥#2!╠9&$@<#5┘#2!╙=&$@='─╥
═#2!╩<╫(@9')┴=╥ [=%=%3%9%(0╘-*┬╚╩*╩!╙5╘%0╚$)51─9%4┼,-#7-╫87!┬
═=68@;&1┴('9═8╫-┬#2!┼;╫(@(╥0╨,┬ [<%)%5%19╚%1224-+62╥@14@_#2!╙
═=&$@=╞╒├<╓(-(&╤─82 ├)# ╪#2!┼;╫(@>╟1┼;7 @.╒╔414╒0/4┴)1╘┬@0┼┼4
═1:!*55-4╚$9,25!3#2!╙=&$@>╟1┼;7 @.╘)%5%=%14┌@)#,╨╚$%.1* ─,╙@-
═#2!╩;7 @;6%╔;┬ [85)/54┘$╚$%.1*!!4─]53─2@5╘6@1╘\╬+┬╪-#0╘╩+2╘═
═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+0╘╩╚'1(25.@4╒5"4─]55$┼.
═1:!#04╤#54╤!5$53╚%1(1:!04─]*14-424].╚$]&╚'┬@04┘$╚'─-#7!╥;╓╔┼
═8╫0@8╓╤├#2!╠9&$@=&<-(&%─8╥!╘: ╘@8╓╤├#2!┴9&,@=&─@.╫1(25.@25.@
═4─]4051%1*!┌#2!├;&,-(&%─8╥ ├,3(╪(#═╫1:!!4─6@1╘])3─>@5$^@5$%+
═1: ╤,├@╦6@╘╩╚#╪^/╩!─96)╒9╓$╠875╪#2╩@/├╪^╚&1┼8╟5╟+"=!)╨╘@=&%╪
═(" [;─]7╚$┼4╚$┼3╚%)%0419╚$9/4╩!)3─1%6$┼.1╨╘@;&1┴('╔─:78╠>" [
═=$%"3$6@3╘:@+40╧6@╘@<╫1┴(&%╒>" [=$┴)4┌!)4┌!&3╒*@5$┴%╚%!23╘╔%
═0╒1)3╘╪-('-╘82!╥96╘@.╓╒53%1)4$╤9╚$-!3╩!#3$]"0─52╚&%╒> ╘-(&-╠
═8╨╘@;&1┴('1┴#2!┴9&,@=&(-(&-╠8╨╘@861├('1├#2!╙=&$@86-├(#═╘2$┼3
═╚$┼3╚%)/5$%4142@6 ╘@:╟-╥('-═=6╤╘(#═╙24=.142@355,5$┼03%╞@86-├
═*╞%╒>"\╥7╞]╞9╟-┼= ╘@8╓╤├#2!╠9&$@86-├#3╔├;╓┘╘,2!┴9&,@(╙8╘(#═╧
═1─93152@5$┴%╚$-/3╒)$24┘!5$4-*╩!╙146@0─5,3╒>@1─]2╚%1(1:!214%3
═3╘┌@5╘┴9╚%1(25,-*╩!.15┴4╚$┼.4╒1254-424].╚$┼3╚$-/34╒%3┼1%1*!/
═550-*╩!╘87┬@╚#═╬3╒>@>*!)4┌!8(0╘@<╫1┴('1╪,0╘@8╓╤├(" [9$^@5$┴%
═╚%=(3╘╤%╚%1(24┘'╚$%'04┼.╚$9/4╩!┘#2!╠9&$@<╞5═#2!╙=&$@875╪#2!╠
═9&$@=&0-(&%─8╥!╘90╘@8╓╤├#2!┴9&,@=&8-('-╘82!┴8╓,@.╫1(25.@25.@
═4─]4051%1*!9#2!╩<╫(@<╓╒╒;'0@.╫-)1╘┘%1*!-54╤425!,6:!┴8╓,╩875╪
═+╙)>;╓9╞<╓5╘#2!├;&,-(&╤─82!┴8╓,-.╞-╧;╟0╥(&%─8╥ ├-├0@.╓]&1┼-%
═5*!42$6@0╘]/4─1)3─%410╘╩╚&9/4╩!33╘╒%╚$-/35!,151%3%╞@54┘+3─]7
═3╩!214%33╘┌@5$^@344-*╩!42$6@24┘35%)50╒1)3╘┌@0─5,3╒>@1$]%4╘╪╟
═5*!73╒)++╩"@<╘]-14┴/5╨╘╩╚%1(1:!╥='.@25.@34]$249924┘'╚'┬@04┘$
═╚'─_/╙\-*╩!╘87╞@╚#═╙5$]21:!)3╩!┘#2!╙=&$@='─╤#2!╥=',@(#═╔╚$┴/
═4$6@5$^@2$5#2┌!42$┼3╚%=/4─═3+@╘-*┬╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═
═+2╘═+2╘═+2╘═+2╘-*╩!╙;75╠=#╩@."╒"252@4╘┼'3─5$╚"┴33╒)4+4]&*:!-
═54╤425!,60╘╩#2╩@86-├*╞%╒>"\╥7╞]╞9╟-┼=* ═/╩!;86-├+*!┼>'1=╚* ╤
═-┬╒"252@4─5354╤4╚*!,3╥╤(20╘╩#2╩@;─]41:!42$%4╚%1(25.@4─]55$┼.
═1:!$259)1$53╚%1(1:!%3─2@4─5354╤4╚$)9╚#)>;╓9╞<╓5╘#0╘╩╚'┼54"╥@
═04┘/5$┴%4╩!-04-23╥╪-9&┼╓;╓9╞(&╒┴8╥ @.╓1)5─┼$1:!"6:!42$6@1─╤/
═052@3╘9&4╘54#2!╠=7 @;╓9╞<╓5╘(#═╥15!%052@3╘9&4╘54╚%1)3453#2!╠
═<╫(@(#═┴╚$-/3┼1!24┘3╚$┴)1╘┬@0┼┼410╘@<╞]╥(&%├8╥ [86-├╚$┼3╚$╤/
═5┌!"651%#2 ═+5╪-(#╨\/ ╘-#7-═=6╤╘(&-╠8╨╘@;&1┴(&%├8╥ [9─┼24╒0╠
═╚$┼3╚%1(1:!215-53%2@4$]3251)5─6@3╒*@3─5'051)5─4_#2!┼;╫(@875╪
═#2!┬;6─@.╞┘┼9╨╘-(&╤─82!┴8╓,@.╫1(15╞@05)%╚$5)5$┴%4╩!"3╒1(╚$┘%
═1╘%4259%╚$]2#2!┬<&╨@.╞-╧;╟0╤(#═"3╒1(╚%!/4╘┼4259%#2!┼;╫(@(╥1╞
═9┬ [:4┌@5$┴)4┌!#05-%+*!-04═%╚%1(14╘-(&%─8╥ ├)# ╤(#═"3╒1(╚%!/
═4╘┼4259%(0╘@<╫1┴(&%├8╨╘@/├╪^(&┘┼9╥╤┴=7@@.╓╤)5%1,1:!-04-23┌!5
═4╘5$╚$5!4─╤)15(╬#3╔├;╓┘╘,2!╠9&$@(╙ ╨(#══54╤425!,6:!42$6@5%=/
═╚$┘534)%4┼,-(&╤─>2 ├)# ┘#5╒╠;╓]╨(&╤╙<┬ @.╫)%042@5$┴%╚$%25$┼#
═3$6@1─]2╚$1%5$%)3%,╬#2!╥;╫(@86-├#2!┬8╓,@.╞╒╒;'0╤(#═╧4╩!&24=5
═4─6@252@3╒54╚%┼/55)314╤&(0╘@8╓╤├#2!┴9&,@875╪#3╔═=6╤╘,2!─97─-
═(&)╬92!=;&]╧< ╘@/├╪^(&1╔=╞]╞9┬ [<─5-3╒9%╚%1(25.@3$┼.1:!&3╒*@
═0:!'14┘%4─%,╚$╒53%1)4$╤9#2!╙=&$@97┴╘#2!╥=',-#3╔╬96<@;&1┴(&%├
═8╥ [;╘┘%╚$]&╚%1(1:!45╘^@25.@3─5'051)5─4-(&)═:2 ┌8╓]╬=#(-(#╪^
═/┬!╬96<╠875╪(#═╧5$┴%4┼=)4╘6@250╟4┌!┴=7@-(&╔═<" ┌8╓]╬=#,-.╞-╧
═;╟0╥(&5╧<┬ ├)&9╞(#═╘04═%╚%173╥=3╚$-/35!,14╒%3┼0-(&%─8╥ ├)# ╤
═#2!╙=&$@86-├#3╔├;╓┘╘,╥!╠9&$@(╙ ╨(#══54╤425!,60╘@;&1┘(",─,#─-
═76╤╧;╫ ╥(&╤╙<@╘@<╞]╥(&%├8╨╘@8╞-├(#╔═=6╤╘,@╘@8╓╤├#2!┴9&,@875╪
═#3╔═=6╤╘,┬!─97─-(&)╬92!=;&]╧<#(-(#╪^/┬!─:79╧9╞8@.╓%'04┼.+*!$
═259)1$6@0┼╞@5$┴%╚$]&1┼-%5 ╘@<╫1┴(&5╪= ╘@;&1┴(&%├8╨╘@8╟!╠(#╔╧
═:╥ [<╘]-151(24┘'╚$┼3╚%)%04╤,6:!74─].1┌!)1╩!42$┼3╚$┼3╚$┘%1╘%4
═259%+@╘@:╟-╥(&-╚;╓═┼#3╔╧:╥!┼;╫(@(╥1╞9┬ [;╒1(15))4╘4╠╚$5615)9
═5$┴)3─>@4─5,159!3┼2@4╘┴/54╤$#2!┴9&,@(╥0╨,2 [0─6@0╘]-4$╤%5$5,
═6:!)3╩!42$6@3$]7╚$)95$4╬#2!╙=&$@86-├#2!╥=',@(#═╔╚$┴/4$4╬+┬╪-
═#2╚═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═#2╩@9╘5.15)!3*!1
═54535$┼/3─%"3$4═5─%,546@15)23╒*@4%)/0╘5$55)%#0╒├:&]╦92!╠9'@@
═(╙ ╨#3╔╠;╓]╨(&╤─82 ┌8╫1┼>'0╠> ╘@8╞5╤(#╔─;╓┘┼#2!╩<╫(@8╓┴╥;╫5╘
═#2!╔;╟@-(&╔═<" ┌;&]╧< ╘┌9&]╬92!╥=',-.╞-╘97┴╘(&┴┼>" ╨9" [8╫(-
═('1╪=" ╟4╘]-151(24┘'╚$-(3╘═%1* ┌*"<-(&┴┼>" ╨9# ╨#0╘╩+2╘═+2╘═
═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+0╘╩╚&1205=)3┬>@0:!,24┘%+╩"@
═8:!&04┴.╚$╤!2$╪╬#0╘╩*┬╩@<╘]-1:!54╘5&54╥@34%#4─]3#0╒╨;&]╘<'@@
═;6%├(" [4$╤/5*!!╚%!/24┘4╚$┼.╚%@-('!╚82 @.╫531:!42$┼3╚$].1:!%
═5─526:!424╒%#2!╠9&$@8╞┼╘<"╤╪(#═╪╚$┼3╚$┼.0╒)%05-%1 ╘@8╟!╠(&,╤
═#2!┼;╫(@8╟5╞9╞5╥#2!╙=&$@8╟5╞9╞5╥#2!┬;6─@8╙(-(&┼╬8╥!┬=69╞97(╦
═,0╒├,┬!╠9&$@(╥4╤,# ╨,# ╨, ╒├,2!╧<╞$@*&)╒9╞9┼<┬─╠>0╘@<╫1┴("┴┬
═=69╞97(╔+'─-('!╠82 @.╓┘%142@5$^@4╘%61:!┴(0╘@/#╨\#0╒╨;&]╘<'─@
═;6%├(" [<$╤/5*!!╚%!/24┘4╚$┼.╚%─┌╚%-)35!,15*@04┘$╚$┘%0╘534╘%2
═62$-('!╚82 @.╫531:!42$┼3╚$].1:!72$5.╚%┼/5:!*55-4╚$┼.0╒)%05-%
═╚'─-(&╤─82!┬:71╨+'@@.╘)55*!╪╚$1/15-.)╒2@0╘┴!3─=%#2!╧<╞$@*&)╒
═9╞9┼<┬─╠>0╘@<╫1┴("┴┬=69╞97(╔+'─-('!╠80╘@/#╨\#0╒├:6┘╔="!═86,@
═(#══04-23┌!43┌!)3─┼424%,25╔%╚%1(1:!#3╒5.5$52#2!╠9&$@73$@.╘18
═╚$]2╚$19#2!╠<╫(-(&5╧<┬ ├)&9╞(#╠╚;─]4╚%173╥=3╚$-/35!,14╒%3┼0╔
═#2!┴9&,@(╥0╨,2 [8: ]╚#(╒-┬╒$6"\╥╚$]2╚#(╒-┬╒$62\╥#2 \/#╨@(#═╘
═2$6@1%@╧,╩!-04═%4┌!!╚$┘)0╘52╚$╤/3╘═)3─>@3$┼.10╘->'-╘97 @;6%├
═(" [;4%#4─^@5$^@5$%+1:!!╚%-415"@24┌@> ╒╪;&]╧<"!╔;╟@-(&%─8╥!─
═>0╘@8╞-├(&╨╤#2╩@9$^@5╘6@55-%╚&┼╬>:!/4╩!─97╞@2$5213\-(&┼╞(&─╠
═73$@.╓┼&╚%1(1:!&25)35*!#2$%204-415*@25.@04┌@)╓─╟#2!╔;╟─-(&5╠
═<╓4-(&1┼>0╘@9╞┼╬#2!╙8╞,@9'@-;#$@/├╪^('!╠;╫1╨>" [84╤705┼3╚%1!
═2╘6@0:!35$50╚$┼.╚'@-(&-╨>"!╪,@╘@8╞┘┼('┴╠;╓]╨#2 \/#╨-#7┼╙=&5╨
═(&╒┴8╥ @.╫-!346@5$┴)3─<╠╚$)55*!&3╒*@>0╒┘;&]╧<"!╔9┬!╔+%╘╤#2!╔
═;╟─-(&5╠<╓4-(&1┼>0╘@8╓╤├(" [=─526:!)35!/4┼1!3┼0┴#2!╞:6╪-(&%─
═8╥!─> ╘@8╞-├(&╨╥#2!╔;╟@@(#═┴3%=!65.@24┘#4─5!4╘6@> ╘@<╓)├(&1┘
═#2 ^/├╪@<&╤╧='!╪#2!╩;7 @;#,-;#(@/├╪^('!╠;╫1╨>2 [=╘6@3╘┘,6:!)
═3─-214%3142@>0╒╠,╥!├<'─@>3(-(&)╬92!┘;&]╧< ╘@/#╨\#0╘╩*┬╚╩╚&┼.
═251)04╥@3$┼.1:!315154 ╘-9')┴=╥ ^/├╪@;6]╓92╤╘>#$[>#$@(#══3╒9%
═╚%-4549&╚$┼.5$^@6─523┌!004=%#2 ^/├╪@;6]╓92╤╘>#([>#(@(#═╫2$52
═1:!)5*!#04┌@0─6@34]$249)140-(#╪^/┬!═;╫9┼+'1┘,3═┘,0╘@/├╪^(&╒╧
═=╞4╠='─╥.╫─╥#2 ^/├╪@<╓5╘8╟5╞(#═╬3╒>@5╘6@0╘%.╚$-,3╘)"15*@5$┴%
═╚$)51─9%4@╘-('-┼8╥ @.╓╒!2╘6@4╒521:!8,3╤8,@╘@;&1┴('@╥#2!╙8╞,@
═>#$-(&)├<╥ ┌8╓]╬= ╘@;&1┴('─╥(#═╔1╩!.3╒0╠╚%-705"@<#&@04┘$╚' ╥
═#2!╠9'─@>3$-('-╘82!┘,0╘@<╫1┘('─╥#2!╠9&$@>#$-(&╤─>2!╪,@╘@<╫1┘
═('@╤#2!╙=&$@>#(-#2!╙8╞,@>#$@.╓┘/5┌!┴/418#3╔├;╓┘╘('-╘82!─> ╘@
═;&1╪('@╤(#═╨552@6#&@24┘43┌!╪+*!.3╒>@5╘6@0╘%.╚%1205-(╚'@╤#0╒├
═;╓╤╒;6╪@;&1┴('@╤(#═╞24┘$╚%1(1:!&25)35*!#3╘╤534┌@1─]2╚'@-(&╤╙
═<┬ @.╥┴╘2$┼3╚$-!3╩!"1:!-041%╚$╒50╘┬@1─%35$52(2─-(&╤╙<┬ @.╫1(
═15)%╚$%21:!8,2\╪╚#$╥.*!"651%╚$),3╘-+4╨╘@;'-╥(" [=╘┴)0╘┬@345!
═3┼.@6#$╧,3:@,├4╓╚$)95$6@0─╤/0╘═3#2!╠<╫(-(&)├8╥ ┌979┼;┬ [=╘┼4
═2*!!╚%!/4╒-)0─╤%╚$585%)!╚#$╥.*!"651%╚$),3╘-+#2!╠9'─@(╥0╪," [
═24:@4╘\╠╚%-%5*!42$6@2$┼'2*!"250-('-╘>2!┬=69╞97(-(&-╠8╨╘┌979┼
═;┬!┴9&,@8╟5╞9╞5╥*╙$@.╓%$1*!)3╩!42$6@3┼5-0─52╚$]&╚#(╒-╩!"651%
═╚$),3╘-+4╨╘@<╫1┴(&)╒9╞9┼<┬╠╤(#═┴3─2@4╒1/4─6@250┴#0╘@<╓5├#2!╠
═9&$@>3(@.╓-!3$-53$%41:!$60╘@<╓)├('─╤#2!┬8╫,@.╞-╧;╟0╥(#═╔4┌!9
═,├┘9,3\-(&╤─82!┘,2 [;╒1(15)725-%╚$19/5─╤+5─╥#2!╙8╞,@>3(-.╞-╧
═;╟0╥('-╘82!─>0╘@8╓╒╨(&1╪(#═╫2$\╟4┌!"24='15(┌╚$19╚$]2╚$18/╨╘@
═8╞-╙('-╘97!╔;╟─@.╓┼&╚$19+*!71:!.145$╚%1/╚%1!2╘6@0─┼'╚%-415!3
═╚$┼.╚%─-#7-╘97!╔;╟@@;&1┘('─╤(#═╪╚$┼3╚$%,4─5!1%╞@4╘54╚%1/╚%@╤
═#2!╠9&$@8╞┼╘<"╤╪(#═╨3$]4╚%1(1:!&25)35*!03╘┼.5 ╘@;╫)┴("┴┬=69╞
═97(╔+'─-('-╘82 ╚8╟5╞9╞5╥*2╤┘#2 ^/├╪@8╓┼╬:70╠9'@@.╓┼.251)04╤)
═6─6@5$┴%╚$-/54┘415(-(&-╨>2!┘,@╘@8╞-╙('┴─96-┘(#═─3┌!71:!35$50
═╚$9/4┼=!4─13╚$]2╚$)!0╘═705)$4┌!)3╩!┘/╨╘->&┼╬8╫─@/├╪^('┴╙=&5╨
═+&┼╬>0╘@<╟1╙#0╒╪9&5├>2 ^/├╪@>'-╘97 ╠9&5┘#2!╥=',-#7-╘97!╔;╟─@
═;&1┘('─╤(#═╫14╤,+*!!╚$╤)5%1,1:!215!%5$┼424].╚$┘%5─52╚$┴54┼2@
═04┘93╘┘%#2!╠9&$@8╞┼╘<"╤╪#2!╧<╞$@*&)╒9╞9┼<┬─╠>0╘@<╫1┴("┴┬=69╞
═97(╔+'─-(#╪^/┬!├:6┘╔="╤─>0╘@8╫!┘('─╥#2!┬8╫,@>61┼8╫─-#7┼╔;╞-┘
═(#╪^/┬!┘<╫1┼<"╤╔;╟─-(')╘<╨╘->61┼8╫─@/├╪^('┼╙=&5╨+&1┼>0╘@<╟1╙
═#0╘-*┬╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘-*╩!├3$5!3╩!5
═4 ╘-8╓╤┼86┘╒<"!╠9&$@=╞╒├<╓(@.╫-7251#2*!#2$%2╚%)/3:!"04-+╚$┼.
═#2!┴;╞0@(╥4╤,3$╤,#$╨,2 [1$5&055,5 ╘@<╫1┴('9═8╫-┬#0╘@<╟1╙(" [
═0┼┼%(0╘-*┬╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘-*╩!╙3╘╒%
═╚%9!4─┼!0─╤%4╨╘-='@╤(&1╙(#$-='─╤(&1╙(#$-='@╥(&1╙(#$-='─╥(&1╙
═(#$-<#%╪(&1╙(#$@.╫1(15-%╚$%21:!414╒03╒)!4┼╞@4╒1/4─%'10╒╨,7─@
═9',@,2 [=5-%1*!)3╩!03$]45$┼.1┌!42$6@4%)/2─5#5$┼/3@╒╨,╟@@9',@
═,0╒╨,╟─@9',@,2 [=$┴%6:!!4─6@2$521:!33┌!42$%4╚%=%#7 ╙>"!─<╥ ╤
═(#═$3╘╪╟5*!(059%╚%1/╚%)%0╘%,0╒5,051%╚%1(14╘╬#7 ╙>2!─<╥ ╤#7 ╘
═>"!─<╥ ╤(#═╘2$59╚$╒!2╘6@3$┼&1:!%05-9+@╒╨-'─@9',@,0╒╨-7@@9',@
═,2 [=╘┴9╚$%21:!93╒6@3$]/2╘┼.1┌!!5*!-1:!,24═%╚%1(050_#7 ╒>2!─
═<╥ ╤(#═─3╘╪╟5*!93╒6@5%)54╒2@344_#7 ╓>"!─<╥ ╤#7 ╓>2!─<╥ ╤(#═╚
═059)3─>@04┘/5$┴%4╩!#2$┼,1*!705-.)╒2@35╞@241%02╪-<#=╪(&1╙(#$-
═<#=┘(&1╙(#$-<#┴╪(&1╙(#$-<#┴┘(&1╙(#$-9'-╪(&1╙(#$@.╓1╙>*!)4┌!4
═2$6@24┘#4─5-14┘4╚$9/4╩!23╒1!5$┼.1┌!!4─]53─2@6 ╒─<╫─@9',@,2 [
═<╘┼-24╤!4╩!&3╒*@9'-┘+*!─<╫╚-9'-┌(&1╙(#$-<╫@@9',@,2 [=$┴%4╘6@
═05)%╚%1(1:!!0╒1504╥@04┘'3$53╚$┼.╚%┬@6:!!3─2@6@╒╙>2!─<╥ ╤#7-┌
═(&1╙(#$-=#$@9',@,2 [=$┴%4╘6@05)%╚%53142@24┌@5$┴%╚%)/5$%424].
═#70╥(&1╙(#$-=#,@9',@,2 [<╘5%╚%1(1:!!4┼1)0╘╤%╚$9/4╩!-3╒)%╚$1%
═5$%)3%,-=#0@9',@,0╒╘-2!─<╥ ╤#70╓(&1╙(#$-=#<@9',@,0╒╘."!─<╥ ╤
═#70┘(&1╙(#$-=#$╨(&1╙(#$-83$╤(&1╙(#$@.╫1(15-%╚$%21:!42$6@14╤%
═345.5%.@3╘:@5$┴%╚%)/5$%424].╚$╒!5%))6 ╒┬,3(@9',@,2 [>'┼┌#6,╤
═,╥!─<╥ ╤#60╥,2!─<╥ ╤(#═╘2$6@3┼5-0─52╚$1%3─]415.@*%)/5╥╤#3╘╤5
═34╪╔#64╥,┬!─<╥ ╤#68╥,╥!─<╥ ╤#6<╙,2!─<╥ ╤#6@╙,┬!─<╥ ╤#6─╙,╥!─
═<╥ ╤#71┴(&1╙(#$@.╫1(15-%╚$%21:!414╒03╒)!4┼╞@3$]#051)3╘┘3#71┬
═(&1╙(#$@.╘9/4╩!54╘6@0┼╞@5$┴%╚%!23╘╔%0╒1)3╘┌@4─]55$┼.10╒╘8╥!─
═<╥ ╤#71─(&1╙(#$-=&4@9',@,0╒╘9┬!─<╥ ╤#71╟(&1╙(#$-=&@@9',@,0╒╘
═:2!─<╥ ╤#0╘╩+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+2╘═+0╘╩╚'-%
═5*!54*!"252@5$%"3$4-#2!─<╥!>(#═├3$5!4╩!43┌!%3─2@3╘:@4$%'10╘@
═(" [<╘^@5$┴!5*!404),15.@4╒1!4┼2@3╘┌@0:!004=%╚$)/54┘$05)9#6)╔
═=' @;'5╨(#$╓(#╠╤,├┬@94┘44─┼%4┌!&3╒*@> ╘@9&9┬("4╤,# ╨,# ╨, ╘@
═9&9┬("4╨,3 ╨,# ╨, ╘@9&9┬("4╨,#$╨,# ╨, ╘@9&9┬("4╨,# ╤,# ╨, ╘@
═9&9┬("4╨,# ╨,3 ╨, ╘@9&9┬("4╨,# ╨,#$╨, ╘@9&9┬("4╨,# ╨,# ╤, ╘@
═9&9┬("4╨,# ╨,# ╨,0╘@+2╒>#7-╔;┬ @(#═╘04),1:!/1╩!324┘%4╥╥@,3(╨
═╚$)95$53#6-╧<╥!┼<74@<╓┼╬*╙$╥." [=$%"3$6@3╘:@0╘]324┘%4╨╘@(" [
═8─]42*!/1╩!42$531:!44─┼'╚%1!0─╤%4┌!!4─4-(" @.╘-54┼)%3┼1,6:!3
═152@55"@1┼)/3:!┬87-╔8╨╒┌9&┼╓(&5╤=2!├;╫,╦,3(╪(#═─259)4╘┼/3╩!4
═04),10╘
#
END
=============================================================================
─┼╙╔╟╬ ╧╞ ┴ '╥┼┴╠' ╧╨┼╥┴╘╔╬╟ ╙┘╙╘┼═ ╞╧╥ ╘╚┼ 128: ╨┴╥╘ ╔
BY ├RAIG ┬RUCE <CSBRUCE@CCNGA.UWATERLOO.CA>
0. ╨╥┼╞┴├┼
╔ ORIGINALLY PLANNED TO WRITE THIS ENTIRE ARTICLE ALL IN ONE GO, BUT ITS
SIZE, COMPLEXITY, AND SCOPE OF REQUIRED DESIGN DECISIONS HAVE FORCED ME TO
SPLIT THIS ARTICLE INTO TWO PIECES. (╬OT TO MENTION MY OWN POOR TIME
MANAGEMENT IN WRITING THIS ARTICLE). ╘HIS PART GIVES AN INTRODUCTION TO WHAT
╔ AM TALKING ABOUT AND DISCUSSES, AT AN ABSTRACT LEVEL, HOW THE SYSTEM WILL
WORK. ╘HE NEXT PART WILL DIVE INTO ALL OF THE NUTS AND BOLTS OF THE
LOW-LEVEL DESIGN.
┴LSO, THIS ARTICLE MAY BE A BIT TO WEIRD FOR SOME PEOPLE TO GRASP. ╨LEASE
BEAR WITH ME. ╘HIS ARTICLE IS AS MUCH A SCRATCHPAD FOR MY ROUGH IDEAS ABOUT
THE KIND OF SYSTEM ╔ WANT TO BUILD AS IT IS AN EXPLANATORY ARTICLE. ┘OU MAY
NEED A ═ASTER'S DEGREE IN SOFTWARE SYSTEMS TO UNDERSTAND SOME OF THE THINGS ╔
TALK ABOUT. ╘HIS ARTICLE MAKES REFERENCES TO THE ┴├┼ OPERATING SYSTEM, WHICH
IS AVAILABLE VIA ANONYMOUS ╞╘╨ FROM "CCNGA.UWATERLOO.CA". ┴├┼ IS A
UNI-TASKING ╧╙ THAT HAS A ╒NIX-LIKE FLAVOR. (┘EAH, YEAH, YEAH, ╔'M STILL
WORKING ON THE NEXT RELEASE...).
╧NE MORE NOTE ABOUT THE ARTICLE: IT IS WRITTEN IN THE PRESENT TENSE ("IS")
RATHER THAN THE FUTURE TENSE ("WILL"), SINCE THE PRESENT TENSE IS EASIER TO
READ AND UNDERSTAND. ╘HE SYSTEM, HOWEVER, DOES NOT PRESENTLY EXIST AND THE
DESIGN MAY CHANGE IN MANY WAYS IF THE SYSTEM EVER IS MADE TO EXIST.
1. ╔╬╘╥╧─╒├╘╔╧╬
╘HE FULL TITLE OF THIS ARTICLE SHOULD BE "─ESIGN OF A ═ULTITASKING ─ISTRIBUTED
═ICROKERNEL ╧PERATING ╙YSTEM FOR THE ╟OOD ╧LD '128". ╞OR PURPOSES OF
DISCUSSION, WE WILL CALL THE NEW OPERATING SYSTEM "┬╧╙". ┴ "MULTITASKING"
OPERATING SYSTEM (╧╙) IS ONE THAT IS ABLE TO EXECUTE MORE THAN ONE "PROCESS"
"CONCURRENTLY". ┴ ╨ROCESS IS AN INSTANCE OF A RUNNING PROGRAM.
"├ONCURRENTLY" MEANS THAT THE PROGRAMS APPEAR TO BE RUNNING AT THE SAME TIME,
ALTHOUGH IN REALITY THEY ARE NOT, BECAUSE THERE IS ONLY "ONE" PROCESSOR IN THE
128 AND IT CAN ONLY DO ONE THING AT A TIME.
┴ "DISTRIBUTED" ╧╙ IS ONE THAT RUNS ON A COLLECTION OF INDEPENDENT COMPUTERS
THAT ARE CONNECTED BY A NETWORK. ╒NLIKE A "NETWORK" ╧╙, A DISTRIBUTED ╧╙
MAKES ALL OF THE INDEPENDENT COMPUTERS LOOK LIKE ╧╬┼ BIG COMPUTER. ╔N
GENERAL, A DISTRIBUTED SYSTEM, AS COMPARED TO A CENTRALIZED ONE (LIKE ═╙-─╧╙
OR ╒NIX), GIVES YOU "A HIGHER PERFORMANCE/PRICE RATIO ('MORE BANG FOR THE
BUCK'), POTENTIALLY INCREASED RELIABILITY AND AVAILABILITY BECAUSE OF PARTIAL
FAILURE MODES (IF PROTOCOLS ARE IMPLEMENTED CORRECTLY), SHARED RESOURCES,
INCREMENTAL GROWTH AND ONLINE EXTENSIBILITY, AND [A CLOSER MODELLING OF] THE
FACT THAT SOME APPLICATIONS ARE INHERENTLY DISTRIBUTED." ╘HIS IS QUOTED FROM
MY ╨H.─. THESIS ABOUT DISTRIBUTED SYSTEMS OF POWERFUL WORKSTATIONS. ╘O US, A
DISTRIBUTED SYSTEM MEANS INCREASED MODULARITY AND EASE OF CONSTRUCTION,
SHARING DEVICES LIKE DISK DRIVES AND RESOURCES LIKE MEMORY BETWEEN MULTIPLE
COMPUTERS, AND THE TRUE PARALLELISM OF RUNNING DIFFERENT PROCESSES ON
MULTIPLE COMPUTERS AT THE SAME TIME. ╬OT TO MENTION "COOLNESS".
┴ "MICROKERNEL" ╧╙ IS ONE THAT HAS THE SMALLEST KERNEL POSSIBLE BY PUSHING
HIGHER-LEVEL FUNCTIONALITY (SUCH AS THE FILE SYSTEM) INTO THE DOMAIN OF USER
PROCESSES. ╘HE KERNEL ENDS UP BEING SMALL, FAST, AND EASY TO CONSTRUCT
(RELATIVE TO A MONOLITHIC KERNEL).
╙O WHY WOULD WE WANT OUR ╧╙ TO HAVE THE FEATURES OF ═ULTITASKING,
─ISTRIBUTED, AND ═ICROKERNEL? ┬ECAUSE ╔'M DESIGNING IT, AND THAT'S WHAT
INTERESTS ME. ╘HE EASE-OF-CONSTRUCTION THING IS IMPORTANT TOO. ┴NOTHER
IMPORTANT QUESTION IS "CAN IT BE DONE?". ╘HE ANSWER IS "YES." ┴ND IT WILL
BE DONE, WHENEVER ╔ GET AROUND TO IT (ONE OF THESE LIFETIMES).
2. ╟┼╬┼╥┴╠ ─┼╙╔╟╬ ╧╓┼╥╓╔┼╫
╘HERE ARE A NUMBER OF HIGH-LEVEL DESIGN DECISIONS THAT MUST BE MADE BEFORE
GOING INTO A DETAILED DESIGN. ╘HIS SECTION DISCUSSES THESE DECISIONS.
2.1. ╙╨┼├╔┴╠ ├-128 ╞┼┴╘╒╥┼╙
╘HE ├-128 HAS A MINUMUM SET OF SPECIAL FEATURES THAT MAKE IT FEASIBLE TO RUN
A MULTITASKING OPERATING SYSTEM, AS OPPOSED TO EARLIER MACHINES LIKE THE
├-64. ╘HE SIMPLEST SPECIAL FEATURE THAT THE ├128 HAS IS *ENOUGH MEMORY*. ╘HE
64╦ OF THE ├64 JUST ISN'T ENOUGH. ╘HE 128╦ OF THE ├128 IS JUST BARELY
ENOUGH. ┼XPANDED INTERNAL MEMORY MAKES THE PROPOSITION EVEN EASIER.
╘HE ├-128 ALSO HAS RELOCATABLE ZERO-PAGE AND STACK-PAGE POINTERS. ╘HIS
FEATURE ARE ABSOLUTELY ESSENTIAL AND YOU COULD NOT MAKE AN EFFECTIVE
MULTITASKING ╧╙ FOR ANY 6502 MACHINE WITHOUT IT. ╔ WONDER IF ├OMMODORE
THOUGHT ABOUT THIS PROSPECT WHEN DESIGNING THE ══╒ CHIP...
╘HE LAST ├-128 FEATURE IS *SPEED*. ╘HE ├128 HAS A 2 ═╚Z CLOCK SPEED WHEN
USED WITH THE 80-COLUMN ╓─├ DISPLAY. ╘HIS IS ENOUGH SPEED, WHEN HARNESSED
PROPERLY, TO MAKE YOUR APPLICATIONS ZIP ALONG. ╞OR AN EXAMPLE OF SPEED THAT
IS NOT HARNESSED PROPERLY, SEE ═ICROSLOTH ╫INDOZE. ╘HE ╓─├ DISPLAY IS ALSO
VERY NICE, TOO. ╧NLY THE ╓─├ DISPLAY SHOULD BE SUPPORTED BY A "REAL" ╧╙, NOT
THE ╓╔├ DISPLAY.
2.2. ╬┼╘╫╧╥╦
╘HE ╧╙ SHOULD BE DESIGNED TO RUN ON A SYSTEM OF BETWEEN 1 AND ╬ ├-128'S,
WHERE ╬ HAS A MAXIMUM OF SOMETHING LIKE 8 OR 16. ╫E'LL CHOOSE 16 FOR OUR
SOFTWARE DESIGN. ╘HE THEORY IS THAT THE STYLE OF OPERATING SYSTEM THAT WE
ARE PROPOSING MAKES THE STEP BETWEEN 1 AND ╬ ├-128'S A (RELATIVELY) EASY ONE,
SO WHY NOT GO FOR IT. ┴LSO, IF ╬ WERE TO BECOME SOME NUMBER LIKE 256 OR
65536, THEN WE COULD START KICKING SOME SERIOUS ASS PERFORMANCE-WISE, FOR
CERTAIN CLASSES OF COMPUTATIONS. ┴LSO, ╔ HAPPEN TO OWN TWO ├-128'S AND ╔
HAVE ALREADY CONSTRUCTED A PARALLEL-PORT NETWORK (A ╩EDI'S WEAPON!), SO ╔
MIGHT AS WELL USE IT.
╘HE REQUIRED NETWORK CONNECTS THE USER PORTS OF ├-128'S INTO A BUS. ╔'M NOT
COMPLETELY SURE HOW TO CONNECT MORE THAN TWO ├-128'S TO THIS BUS (╔'D
PROBABLY NEED SOME DIODES OR LOGIC GATES), SO THE INITIAL VERSION OF THIS
NETWORK HARDWARE WILL HAVE A MAXIMUM OF TWO HOSTS. ╫E WILL STILL BE CAREFUL
TO MAKE THE SOFTWARE OF THE SYSTEM EASILY RECONFIGURABLE FOR ANY NUMBER OF
HOSTS.
┘OU WILL NEED TWO APPROPRIATE CONNECTORS AND SOME 14-CONDUCTOR RIBBON CABLE
TO BUILD THE NETWORK. ╧NE OF MY CONNECTORS IS A 44-CONDUCTOR CONNECTOR OF
THE TYPE USED WITH THE ╓╔├-20 EXPANSION PORT THAT ╔ SAWED IN HALF AND THE
CABLE IS SOME OLD JUNK RIBBON CABLE THAT WAS LYING AROUND THAT ╔ REMOVED SOME
OF THE CONDUCTORS FROM. ┴NY OLD JUNK WILL DO. ┘OU'RE PROBABLY BEST OFF IF
YOUR CABLE IS LESS THAN SIX FEET LONG (2 METRES). ╘HE NETWORK IS WIRED UP AS
FOLLOWS:
├128-┴ NAME/PIN PIN/NAME ├128-┬
╟╬─ <┴>+------------------------------------+<┴> ╟╬─
╞╠┴╟ <┬>+------------------------------------+<8> ╨├2 ***
╨┬0 <├>+------------------------------------+<├> ╨┬0
╨┬1 <─>+------------------------------------+<─> ╨┬1
╨┬2 <┼>+------------------------------------+<┼> ╨┬2
╨┬3 <╞>+------------------------------------+<╞> ╨┬3
╨┬4 <╚>+------------------------------------+<╚> ╨┬4
╨┬5 <╩>+------------------------------------+<╩> ╨┬5
╨┬6 <╦>+------------------------------------+<╦> ╨┬6
╨┬7 <╠>+------------------------------------+<╠> ╨┬7
╨┴2 <═>+------------------------------------+<═> ╨┴2
╟╬─ <╬>+------------------------------------+<╬> ╟╬─
├╬╘2 <6>+------------------------------------+<6> ├╬╘2
╙╨2 <7>+------------------------------------+<7> ╙╨2
╨├2 <8>+------------------------------------+<┬> ╞╠┴╟ ***
╚ERE IS THE ├OMMODORE 128 ╒SER ╨ORT WHEN LOOKING AT THE BACK OF THE UNIT:
111
123456789012 TOP
------------
┴┬├─┼╞╚╩╦╠═╬ BOTTOM
╘HIS GIVES A PARALLEL BUS THAT CAN OPERATE AT A PEAK OF ABOUT 80
KILO┬┘╘┼╙/SEC WITH A SHIFT-REGISTER SERIAL BUS THROWN IN THAT CAN OPERATE AT
A PEAK OF ABOUT 21 KILO┬┘╘┼╙/SEC. ┬OTH COMMUNICATION CHANNELS ARE
UNI-DIRECTIONAL, SO SOME MEDIA-ACCESS-CONTROL PROTOCOL WILL NEED TO BE
PROVIDED BY SOFTWARE. ╘HE PRICE, IN TERMS OF HARDWARE FOR USING THIS
NETWORK, IS THAT YOU CAN'T USE A MODEM THAT PLUGS INTO THE USER PORT AT THE
SAME TIME. ╧F COURSE, ANY SERIOUS USER WILL HAVE A MODEM THAT PLUGS INTO A
╒┴╥╘ CARD ANYWAY.
┘OU CAN ALSO WRITE YOUR OWN APPLICATIONS FOR THIS NETWORK, SINCE PROGRAMMING
IT IS QUITE EASY; THE HARDWARE TAKES CARE OF ALL OF THE HANDSHAKING. ╘O
BLAST 256 BYTES OVER THE NETWORK FROM ├128-┴ TO ├128-┬, YOU WOULD:
├128-┴: SENDER ├128-┬: RECEIVER
============== ================
LDA #$╞╞ ;DDR-OUTPUT LDA #$00 ;DDR-INPUT
STA $──03 STA $──03
LDY #0 LDY #0
- LDA ─┴╘┴,Y ;GET DATA - LDA #$10 ;WAIT FOR DATA
STA $──01 ;SEND DATA - BIT $──0─
LDA #$10 ;WAIT FOR ACK BEQ -
- BIT $──0─ LDA $──01 ;RECEIVE DATA/SEND ACK
BEQ - STA ─┴╘┴,Y ;STORE DATA
INY ;NEXT INY
BNE -- BNE --
RTS RTS
╘HESE ROUTINES CAN EVEN BE TWEAKED A LITTLE MORE FOR HIGHER PERFORMANCE.
╨ROGRAMMING THE SHIFT REGISTER IS ANALOGOUS TO THE ABOVE.
╘HERE IS PROBABLY NO NEED TO DO ERROR CHECKING ON THE DATA TRANSMITTED OVER
THE NETWORK SINCE THE CABLE SHOULD BE ABOUT AS RELIABLE AS ANY OF THE OTHER
CABLES HANGING OUT THE BACK OF YOUR COMPUTER (AND NONE OF THEM HAVE ERROR
CHECKING (EXCEPT MAYBE YOUR MODEM CABLE)).
2.3. ╨╥╧├┼╙╙┼╙
┴ PROCESS IS A USER PROGRAM THAT IS IN AN ACTIVE STATE OF EXECUTION. ╔N
UNI-TASKING OPERATING SYSTEMS LIKE ┴├┼ OR THE ├OMMODORE ╦ERNAL, THERE IS ONLY
ONE PROCESS IN THE ENTIRE SYSTEM. ╔N A MULTI-TASKING SYSTEM, THERE ARE, DUH,
MULTIPLE PROCESSES. ┼ACH PROCESS EXECUTES AS AN INDEPENDENTLY RUNNING
PROGRAM, IN ISOLATION, LOGICALLY AS IF IT WERE THE ONLY PROCESS IN THE
SYSTEM. ╧R, AS IF THERE WERE ╬ 8502'S AVAILABLE INSIDE OF THE 128 AND ONE OF
THEM WERE USED TO RUN EACH PROGRAM YOU HAVE LOADED.
╔N REALITY, THERE IS ONLY 1 ├╨╒ IN THE 128 (WELL, THAT WE ARE INTERESTED IN
USING), SO ITS TIME IS DIVIDED UP AND GIVEN OUT IN SMALL CHUNKS TO EXECUTE SO
MANY INSTRUCTIONS OF EACH PROGRAM BEFORE MOVING ONTO THE NEXT ONE. ╘HE ACT
OF CHANGING FROM EXECUTING ONE PROGRAM TO EXECUTING ANOTHER IS CALLED
"CONTEXT SWITCHING", AND IS A BIT OF A STICKY BUSINESS BECAUSE THERE IS ONLY
ONE SET OF PROCESSOR REGISTERS, SO THESE MUST BE SAVED AND RESTORED EVERY
TIME WE SWITCH BETWEEN PROCESSES. ┼FFECTIVELY, A PROCESS' COMPLETE "STATE"
MUST BE RESTORED AND SAVED EVERY TIME IT IS ACTIVATED AND DEACTIVATED
(RESPECTIVELY). ╙INCE THE 8502 HAS PRECIOUS FEW INTERNAL REGISTERS, CONTEXT
SWITCHING CAN BE DONE QUITE EFFICIENTLY (UNLIKE WITH SOME ╥╔╙├ PROCESSORS).
╘HE MAXIMUM PERIOD OF TIME BETWEEN CONTEXT SWITCHES IS CALLED THE "QUANTUM"
TIME. ╔N OUR SYSTEM, THE QUANTUM IS 1/60 OF A SECOND. ╔T IS MORE THAN JUST
A COINCIDENCE THAT THIS PERIOD IS THE SAME AS THE KEYBOARD-SCANNING PERIOD.
─EPENDING ON PRIORITIES AND READY PROCESSES, A NEW OR THE SAME OLD PROCESS
MAY BE SELECTED FOR EXECUTION AFTER THE CONTEXT SWITCH OF THE 60-╚Z
INTERRUPT.
╙PLITTING THE TIME OF ONE PROCESSOR AMONG ╬ PROCESSES MAY SOUND LIKE WE'RE
SIMPLY MAKING EACH ONE RUN ╬ TIMES SLOWER, WHICH MAY BE UNBEARABLY SLOW, BUT
THAT IS NOT GENERALLY THE CASE. ╧NE THING THAT A ├╨╒ SPENDS A LOT OF ITS
TIME DOING IS *WAITING*. ┼XECUTING INSTRUCTIONS OF A PROGRAM REQUIRES THE
FULL ATTENTION OF THE ├╨╒, BUT WAITING REQUIRES ABSOLUTELY NO ├╨╒ ATTENTION.
┴S AN EXAMPLE, YOUR SPEEDY COMPUTER SPENDS A LOT OF ITS TIME WAITING FOR ITS
SLOW-AS-MOLASSES-LAUNCHING-INTO-ORBIT USER TO TYPE A KEY. ╔F WE WERE TO PUT
THE PROCESS THAT ASKS THE ╧╙ FOR A KEYSTROKE INTO A STATE OF SUSPENDED
ANIMATION, THEN THE ├╨╒ TIME THAT PROCESS WOULD HAVE CONSUMED IN A
BUSY-WAITING LOOP CAN BE BETTER SPENT ON EXECUTING THE OTHER PROCESSES THAT
ARE "READY" TO EXECUTE. ╔N PRACTICE, MANY PROCESSES SPEND A LOT OF THEIR
TIME WAITING, SO "MULTI-PROGRAMMING" IS A BIG WIN.
╘HERE ARE A NUMBER OF THINGS OTHER THAN KEYSTROKES THAT PROCESSES MAY WAIT
FOR IN OUR ENVISIONED SYSTEM: MODEM CHARACTERS, DISK DRIVE OPERATIONS (IF
THEY ARE CUSTOM-PROGRAMMED CORRECTLY), MOUSE & JOYSTICK MOVEMENTS, REAL-TIME
DELAYS, AND INTERACTIONS WITH OTHER PROCESSES. ╘HE ╧╙ PROVIDES FACILITIES
FOR PROCESSES TO COMMUNICATE WITH ONE ANOTHER WHEN THEY CANNOT PERFORM SOME
OPERATION IN ISOLATION (I.E., WHEN THEY BECOME LONELY).
┴ PROCESS HAS THE FOLLOWING THINGS: A PROGRAM LOADED INTO THE INTERNAL MEMORY
OF THE 128, ITS OWN ZERO PAGE AND PROCESSOR STACK PAGE, AND THE GLOBAL
VARIABLES OF ITS PROGRAM. ┴ PROCESS CAN ALSO OWN "FAR" MEMORY (BELOW) AND
VARIOUS OTHER RESOURCES OF SERVERS THROUGHOUT THE DISTRIBUTED SYSTEM. ╘HE
PROCESS IS THE UNIT OF OWNERSHIP, AS WELL AS EXECUTION. ╨ROCESSES ALSO HAVE
PRIORITIES THAT DETERMINE HOW MUCH EXECUTION TIME THEY ARE TO BE GIVEN
RELATIVE TO OTHER PROCESSES IN THE SYSTEM.
╨ROCESSES ARE ALLOCATED MEMORY AT THE TIME OF STARTUP AT A RANDOM LOCATION ON
SOME RANDOM BANK OF INTERNAL MEMORY ON THE 128. ╘HE BIGGEST CHALLENGE HERE
IS TO RELOCATE THE USER PROGRAM TO EXECUTE AT THE CHOSEN ADDRESS. ╘HE KERNEL
INTERFACE IS AVAILABLE TO PROGRAMS ON ALL INTERNAL BANKS OF MEMORY.
2.4. ┴╨╨╠╔├┴╘╔╧╬ ╨╥╧╟╥┴═ ╔╬╘┼╥╞┴├┼
╘O TAKE ADVANTAGE OF EXISTING SOFTWARE, WE WOULD LIKE OUR ╧╙ TO PROVIDE AN
APPLICATION-PROGRAM INTERFACE (┴╨╔) THAT IS IDENTICAL TO THAT OF THE
┴├┼-128/64 OPERATING SYSTEM. ╔N FACT, THIS IS THE *REAL* REASON WHY ┴├┼ WAS
DEVELOPED -- AS A STEPPING STONE TOWARD A REAL OPERATING SYSTEM. ╘HE ┴├┼
╨ROGRAMMER'S ╥EFERENCE ╟UIDE, WHICH DESCRIBES THE ┴╨╔, IS AVAILABLE FROM
"CCNGA.UWATERLOO.CA".
╙OME USEFUL SOFTWARE ALREADY EXISTS FOR ┴├┼, AND ┴├┼ HAS A WELL-DEFINIED
INTERFACE AND WELL-BEHAVED PROGRAMS. ╘HE ┴├┼ INTERFACE MAY NEED TO EVOLVE A
LITTLE TOO. ╘HE ULTIMATE GOAL WOULD BE TO HAVE THE SAME ┴╨╔ FOR BOTH SYSTEMS
SO YOU COULD RUN SOFTWARE WITH THE MORE FUNCTIONAL ┬╧╙ IF YOU HAVE A ├128 AND
80-COLUMN MONITOR, OR YOU COULD USE THE LESS FUNCTIONAL ┴├┼ IF YOU DIDN'T
HAVE ALL THIS HARDWARE.
╘HE SOFTWARE WOULDN'T BE "BINARY-IDENTICAL" SINCE THE OPERATING SYSTEMS
PROVIDE QUITE DIFFERENT PROGRAM ENVIRONMENTS AND REQUIREMENTS, BUT THE TWO
SYSTEMS SHOULD BE APPLICATION-SOURCE-CODE COMPATIBLE.
┬ECAUSE OF THE VAST DIFFERENCES BETWEEN A MICROKERNEL AND A MONOLITHIC
KERNEL, ALL OF THE ┴├┼ SYSTEM CALLS WOULD BE REDIRECTED TO USER-LIBRARY CALLS
IN ┬╧╙. ╘HIS USER LIBRARY WOULD THEN CARRY OUT THE OPERATIONS ACCESSING
WHATEVER SYSTEM SERVICES ARE NEEDED.
2.5. ═┼═╧╥┘ ═┴╬┴╟┼═┼╬╘
╘HE MEMORY MANAGEMENT OF ┬╧╙ IS ANALOGOUS TO THAT OF ┴├┼. ╘HERE ARE TWO
DIFFERENT CLASSES OF MEMORY: NEAR AND FAR. ╬EAR MEMORY IS ON THE SAME BANK
AS A PROGRAM AND CAN BE ACCESSED DIRECTLY BY PROCESSOR INSTRUCTIONS. ╞AR
MEMORY CAN ONLY BE ACCESSED THROUGH THE KERNEL BY THE SPECIAL KERNEL CALLS
╞ETCH AND ╙TASH AND MUST BE SPECIALLY ALLOCATED TO A PROCESS BY THE OPERATING
SYSTEM. ╬OTE THAT NEAR MEMORY IS CONSIDERED A SUB-CLASS OF FAR MEMORY; THE
FAR-MEMORY PRIMITIVES CAN BE USED TO ACCESS NEAR MEMORY.
╧NLY THE BASIC MEMORY-ACCESSING CODE IS PROVIDED BY THE KERNEL; HIGHER-LEVEL
MEMORY MANAGEMENT, SUCH AS DYNAMIC MEMORY ALLOCATION AND DEALLOCATION, IS
HANDLED BY THE ═EMORY ╙ERVER (BELOW).
╒NLIKE ┴├┼, ┬╧╙ PROVIDES THE FUNDAMENTAL CONCEPT OF "DISTRIBUTED MEMORY".
╘HE ╞ETCH AND ╙TASH PRIMITIVES CAN ALSO ACCESS THE MEMORY OF A REMOTE MACHINE
IN A COMPLETELY USER-TRANSPARENT WAY. ╘HUS, A FAR-MEMORY POINTER CAN BE
PASSED BETWEEN PROCESSES ON DIFFERENT MACHINES, AND THE MEMORY THAT THE
POINTER REFERS TO CAN BE READ AND WRITTEN WITH EQUAL PROGRAMMING BY BOTH
PROCESSES. ╘HIS FEATURE CAN BE DANGEROUS WITHOUT A SYNCHRONIZATION MECHANISM,
SO THIS MEMORY SHARING IS INTENDED TO BE USED ONLY WITH THE COMMUNICATION
MECHANISM.
╘HERE SHOULD NOT BE AN UNACCEPTABLE OVERHEAD IN ACCESSING REMOTE MEMORY ON
THE 128 (LIKE HOW THERE WOULD BE WITH BIGGER COMPUTERS) BECAUSE FAR-MEMORY
FETCHING FOR LOCAL MEMORY IS QUITE EXPENSIVE ANYWAYS (RELATIVE TO NEAR
MEMORY), SO AN APPLICATION WILL OPTIMIZE ITS FAR MEMORY ACCESSING, AND THE
NECESSARY INTERRUPT HANDLING ON THE REMOTE MACHINE CAN BE DONE WITH VERY
LITTLE LATENCY BECAUSE OF THE "RESPONSIVENESS" OF THE 6502 PROCESSOR DESIGN.
2.6. ├╧══╒╬╔├┴╘╔╧╬
╔N THE TYPE OF SYSTEM THAT IS ENVISIONED, PROCESSES ARE NOT STRICTLY
INDEPENDENT AND COMPETITIVE; MANY MUST COOPERATE AND COMUNICATE TO GET WORK
DONE. ╘O FACILITIATE THIS INTERPROCESS COMMUNICATION (╔╨├), A PARTICULAR
ORGANIZATION IS CHOSEN: THE ╥EMOTE ╨ROCEDURE ├ALL (╥╨├) PARADIGM. ╥╨├ IS A
MESSAGE-PASSING SCHEME THAT IS USED WITH THE HEAVILY HYPED ├LIENT/╙ERVER
SYSTEM ARCHITECTURE MODEL. ╔T REFLECTS THE IMPLICIT OPERATIONS THAT TAKE
PLACE WHEN YOU CALL A LOCAL PROCEDURE (A SUBROUTINE): THE CALL, THE ENTRY,
THE PROCESSING, AND THE RETURN. ╘HE KERNEL PROVIDES THREE PRIMITIVES FOR
╥╨├:
╙END( PROCESS╔D, REQUEST┬UFFER, REQ╠ENGTH, REPLY┬UFFER, MAX╥EP╠ENGTH ) : ERR;
╥ECEIVE( ) : PROCESS╔D, REQUEST┬UFFER, REQ╠ENGTH, REPLY┬UFFER, MAX╥EP╠ENGTH;
╥EPLY( PROCESS╔D ) : ERR;
╙END() IS USED TO TRANSMIT A MESSAGE TO A REMOTE PROCESS AND GET BACK A REPLY
MESSAGE. ╘HE SENDING PROCESS SUSPENDS ITS EXECUTION WHILE IT IS WAITING FOR
REMOTE PROCESS TO EXECUTE ITS REQUEST. ┴ MESSAGE CONSISTS OF AN ARBITRARY
SEQUENCE OF BYTES WHOSE MEANING IS COMPLETELY DEFINED BY THE USER. ╘HE
MESSAGE CONTENTS ARE STORED IN A BUFFER (HUNK OF MEMORY) BEFORE SENDING, AND
A LENGTH IS SPECIFIED AT THE TIME OF SENDING. ┴ BUFFER TO RECEIVE THE REPLY
MESSAGE MUST ALSO BE ALLOCATED BY THE SENDER AND SPECIFIED AT THE TIME OF
SENDING. ╘O SAVE US FROM THE OVERHEAD OF COPYING MESSAGE CONTENTS TO AND FRO
UNNECESSARILY, ONLY POINTERS TO THE BUFFERS ARE PASSED AROUND AND THE FAR
MEMORY PRIMITIVES ARE USED TO ACCESS MESSAGE CONTENTS. ╘HIS ALSO WORKS
ACROSS MACHINE BOUNDARIES BECAUSE OF THE DISTRIBUTED-MEMORY MECHANISM
DESCRIBED ABOVE.
╥ECEIVE() IS USED TO RECEIVE A MESSAGE TRANSMITTED BY A REMOTE PROCESS TO THE
CURRENT PROCESS. ╘HE RECEIVER BLOCKS UNTIL ANOTHER PROCESS DOES A
CORRESPONDING ╙END() OPERATION, AND THEN THE REQUEST AND REPLY BUFFER
POINTERS AND LENGTHS ARE RETURNED. ╘HE RECEIVER IS EXPECTED TO FETCH THE
CONTENTS OF THE REQUEST MESSAGE, PROCESS THE REQUEST, PREPARE THE REPLY
MESSAGE IN THE FAR-MEMORY REPLY BUFFER, AND THEN EXECUTE THE ╥EPLY()
PRIMITIVE. ╘HERE ARE NO RESTRICTIONS ON WHAT THE RECEIVER CAN DO BETWEEN
RECEIVING A MESSAGE FROM A PROCESS AND ISSUING THE CORRESPONDING REPLY
MESSAGE. ╙O, IT COULD, FOR EXAMPLE, RECEIVE AND PROCESS MESSAGES FROM OTHER
PROCESSES UNTIL IT GETS WHAT IT NEEDS, COMPUTE PI TO 10_000 DECIMAL PLACES,
AND THEN REPLY TO THE PROCESS THAT SENT A MESSAGE TO IT A LONG TIME AGO.
╥EPLY() IS USED TO RE-AWAKEN A PROCESS THAT SENT A MESSAGE THAT WAS
╥ECEIVE()D BY THE CURRENT PROCESS. ╘HE CURRENT PROCESS IS EXPECTED TO HAVE
SET UP THE FAR-MEMORY REPLY BUFFER IN WHATEVER WAY THE SENDING PROCESS
REQUIRES PRIOR TO ISSUING THE ╥EPLY().
╘HE EXPECTED USAGE OF BUFFERS IS FOR THE SENDER TO USE NEAR MEMORY FOR THE
REQUEST AND REPLY BUFFERS AND ACCESS THEM AS REGULAR NEAR MEMORY TO CONSTRUCT
AND INTERPRET REQUEST AND REPLY MESSAGES. ╘HE RECEIVER WILL ACCESS THE
BUFFERS AS FAR MEMORY (WHICH THEY MAY VERY WELL BE SINCE PROCESSES ARE
ALLOWED TO EXECUTE ON DIFFERENT BANKS OF INTERNAL MEMORY AND EVEN ON
DIFFERENT MACHINES), AND MAY WISH TO FETCH PARTS OF MESSAGES INTO NEAR MEMORY
FOR PROCESSING. ╘HE USE OF FAR POINTERS MAKES IT SO THAT DATA IS COPIED ONLY
WHEN NECESSARY.
┴ND THAT'S IT. ┘OU ONLY HAVE THIS ╥╨├ MECHANISM FOR COMMUNICATING WITH OTHER
PROCESSES AND FOR ALL ╔/╧. ╫ELL, THAT'S NOT ENTIRELY TRUE; THE ╥╨├ STUFF IS
HIDDEN BEHIND THE APPLICATION PROGRAM INTERFACE, WHICH PROVIDES SUCH FACADES
AS THE ╧PEN AND ╥EAD SYSTEM CALLS, AND A VERY-LOW LEVEL INTERRUPT
NOTIFICATION MECHANISM WHICH A USER PROCESS WILL NOT NORMALLY USE.
2.7. ╙┘╙╘┼═ ╙┼╥╓┼╥╙
╙INCE ALL THAT USER PROGRAM HAS FOR ╔╨├ AND ╔/╧ IS THE ╥╨├ MECHANISM, A
NUMBER OF SYSTEM SERVER PROCESSES MUST BE SET UP TO ALLOW A USER PROGRAM TO
DO ANYTHING USEFUL. ╘HESE SPECIAL SERVERS EXECUTE AS IF THEY WERE REGULAR
USER PROGRAMS BUT PROVIDE SERVICE THAT IS NORMALLY IMPLEMENTED DIRECTLY INTO
THE OPERATING SYSTEM KERNEL. ╘HERE ARE A NUMBER OF ADVANTAGES AND
DISADVANTAGES TO ORGANIZING A SYSTEM IN THIS WAY. ┴ BIG ADVANTAGE IS THAT IT
IS EASIER TO BUILD A MODULAR SYSTEM LIKE THIS, AND A BIG DISADVANTAGE IS THAT
YOU LOSE SOME PERFORMANCE TO THE OVERHEAD OF THE ╔╨├ MECHANISM.
┴ USEFUL IMPLICATION OF USING SERVERS RATHER THAN HAVING USER PROCESSES
EXECUTE INSIDE OF THE KERNEL IS MUTUAL EXCLUSION. ╙ERVERS EFFECTIVELY
SERIALIZE USER REQUESTS. ╔.E., USER REQUESTS ARE SERVICED IN ORDER, STRICTLY
ONE-AT-A-TIME. ╘HIS IS IMPORTANT BECAUSE SOME OF VARIABLES THAT NEED TO BE
MANIPULATED IN ORDER TO PROVIDE SERVICE MUST NOT BE MANIPULATED BY MULTIPLE
PROCESSES SIMULTANEOUSLY OR YOU MAY GET INCONSISTENT RESULTS. ╘O PROVIDE
MUTUALLY EXCLUSIVE ACCESS TO SHARED VARIABLES IN A MONOLITHIC SYSTEM, EITHER
UGLY AND PROBLEMATIC SEMAPHORES MUST BE USED, OR MORE-RESTRICTIVE, SIMPLER
MECHANISMS LIKE ALLOWING ONLY ONE USER PROCESS TO ENTER THE KERNEL.
2.7.1. ╨╥╧├┼╙╙ ╙┼╥╓┼╥
╘HIS SERVER IS RESPONSIBLE FOR STARTING AND TERMINATING USER PROCESSES.
┬ECAUSE OF THE WAY THAT THE PROCEDURE IS ORGANIZED, THE PROCESS SERVER IS
ACTUALLY QUITE RESPONSIVE DISPITE ALL OF THE WORK THAT MUST BE DONE IN ORDER
TO START UP AND TERMINATE A USER PROCESS.
╘HE SERVER IS HIGHLY INTEGRATED WITH THE KERNEL, AND IT IS ABLE TO DO THINGS
THAT REGULAR USER PROCESSES CANNOT (LIKE MANIPULATE KERNEL DATA STRUCTURES),
BUT IT STILL FUNCTIONS AS AN INDEPENDENT ENTITY, AS A REGULAR USER PROCESS.
╔TS CODE IS PHYSICALLY A PART OF THE KERNEL FOR BOOTSTRAPPING PURPOSES, SINCE
IT CAN HARDLY BE USED TO START ITSELF.
╫HEN YOU WISH TO RUN A NEW PROGRAM, A REQUEST MESSAGE IS SENT TO THE PROCESS
SERVER. ╘HIS MESSAGE INCLUDES THE FILENAME OF THE PROGRAM TO RUN, THE
ARGUMENTS TO THE NEW PROGRAM, ENVIRONMENTAL VARIABLES, AND A SYNCHRONOUS/
ASYNCHRONOUS FLAG. ╔F YOU WANT TO RUN A SUB-PROCESS SYNCHRONOUSLY, THE
PROCESS SERVER DOES NOT REPLY TO YOUR REQUEST UNTIL THE NEW PROCESS
TERMINATES. ╔F YOU SELECT ASYNCHRONOUS MODE, THE PROCESS SERVER REPLIES TO
YOUR REQUEST AS SOON AS THE NEW PROCESS IS CREATED. ┬OTH OF THESE MODES ARE
QUITE USEFUL IN ╒NIX (ALTHOUGH ╒NIX HAS A MORE COMPLICATED MECHANISM FOR
PROVIDING THE SERVICE) (THINK "&" AND NO-"&" ON COMMAND LINES), SO THEY ARE
PROVIDED HERE.
╘HE PROCESS SERVER ALLOCATES AND INITIALIZES THE KERNEL DATA STRUCTURES
NECESSARY FOR PROCESS MANAGEMENT, AND THEN STARTS THE PROCESS RUNNING
BOOTSTRAPPING CODE IN THE KERNEL. ╙INCE THIS CODE IS IN THE KERNEL, IT IS
KNOWN TO BE TRUSTWORTHY. ╘HE PROCESS THEN BOOTSTRAPS ITSELF BY OPENING THE
PROGRAM FILE, READING THE MEMORY REQUIREMENTS, ALLOCATING SUFFICIENT MEMORY,
READING IN THE PROGRAM FILE, RELOCATING THE PROGRAM FOR WHATEVER MEMORY
ADDRESS IT HAPPENED TO LOAD IN AT (BANK RELOCATION IS NO PROBLEM) AND
FAR-CALLING THE MAIN ROUTINE (FINALLY). ╘HE RETURN IS SET UP ON THE STACK TO
KILL THE PROCESS.
╙INCE THE PROCESS BOOTSTRAPS ITSELF, THE PROCESS SERVER'S INVOLVEMENT IN THE
PROCESS CREATION PROCEDURE IS MINIMAL, AND THE PROCESS SERVER IS READY TO
PROCESS NEW REQUESTS WITH MINIMAL DELAY (MAXIMAL RESPONSIVENESS). ╘HIS
SELF-BOOTSTRAPPING USER PROCESS CONCEPT COMES FROM MY ═ASTER'S ╘HESIS.
┴NOTHER ADVANTAGE OF HAVING A PROCESS SERVER IS THAT YOU CAN START A PROCESS
RUNNING ON ANY MACHINE FROM ANY OTHER MACHINE IN EXACTLY THE SAME WAY YOU
WOULD START A PROCESS ON THE LOCAL MACHINE; WE HAVE ACHIEVED TRANSPARENTNESS,
╨ARK.
╘HE PROCESS SERVER ALSO TAKES CARE OF PROCESS DESTRUCTION (EXIT OR KILL) AND
PROVIDES OTHER LESS-SIGNIFICANT SERVICES, LIKE READING AND SETTING THE
CURRENT DATE AND TIME. ╘HE MECHANISM BY WHICH PROCESS DESTRUCTION IS DONE IS
SIMILAR TO THE SELF-BOOTSTRAPPING IDEA AND IS DISCUSSED, PROBABLY
INAPPROPRIATELY, IN THE NEXT SECTION.
╘HE SERVER IS LOCATED BY HAVING A WELL-KNOWN ADDRESS. ╘HAT IS, THE PROCESS
ID IS A CONSTANT AND HARD-CODED INTO CLIENTS. ╫ELL-KNOWN ADDRESSES ARE SMALL
INTEGER VALUES, FOR EACH MACHINE (A MACHINE-ID IS ENCODED INTO PROCESS IDS),
AND THESE INTEGERS ARE INDEXES INTO A SMALL LOOK-UP TABLE WITH THE ACTUAL
ADDRESSES FOR WELL-KNOWN ADDRESSES, SO THE PROCESS IDS AREN'T PINNED BUT CAN
BE USED AS IF THEY WERE PINNED.
2.7.2. ═┼═╧╥┘ ╙┼╥╓┼╥
╘HE MEMORY SERVER HANDLES THE DYNAMIC ALLOCATION AND DEALLOCATION OF FAR
MEMORY. ╘HE CLIENT SPECIFIES IN THE REQUEST MESSAGE THE EXACT TYPES OF
MEMORY THAT IT CAN USE, AND THE SERVER GETS THE MEMORY, SETS THE OWNERSHIP TO
THE PROCESS, AND RETURNS A POINTER. ─EALLOCATION OF SOME OF THE MEMORY OWNED
BY A PROCESS IS HANDLED EASILY.
╘HERE IS ALSO A CALL THAT DEALLOCATES ALL MEMORY OWNED BY A CERTAIN USER
PROCESS. ╘HIS CALL IS NORMALLY ONLY CALLED BY THE PROCESS SERVER*, SINCE THE
MEMORY OF THE USER PROGRAM IS BE DEALLOCATED ALONG WITH THE REST OF THE
PROCESS' MEMORY. ┴ RECORD IS KEPT INTERNALLY FOR EACH PROCESS ABOUT WHAT
TYPES AND BANKS (LATER) OF MEMORY IT HAS USED SO THAT BULK DEALLOCATION CAN
BE DONE EFFICIENTLY WHEN THE PROCESS EXITS.
┴ CLIENT PROCESS CAN ALSO ASK THAT FAR MEMORY BE ALLOCATED ON A REMOTE
MACHINE. ╥EMOTE MEMORY IS RELATIVELY SLOW TO ACCESS, BUT IT CAN BE
CONVENIENT WHEN YOU NEED ╠╧╘╙ OF MEMORY FOR A PROCESS. ╘HE OBVIOUS WAY TO
GET AT THIS REMOTE MEMORY IS TO SIMPLY SEND A MESSAGE DIRECTLY TO THE REMOTE
MEMORY SERVER OF THE MACHINE YOU WANT TO ALLOCATE MEMORY ON, AND THIS DOES
INDEED WORK, SO THIS IS WHAT WE WILL DO. ┬UT, THIS DOESN'T RECORD THE FACT
THAT YOU HAVE ALLOCATED MEMORY ON A FAR MACHINE BY ITSELF, AND WE DON'T WANT
TO WASTE ANY EFFORT IN FREEING ALL OF THE MEMORY, BOTH LOCAL AND REMOTE, THAT
A PROCESS OWNS WHEN IT TERMINATES; I.E., WE DON'T WANT TO SEND DEALLOCATION
REQUESTS TO ALL REMOTE MEMORY SERVERS JUST TO BE SURE.
╘HERE ARE A FEW ALTERNATIVES FOR SOLVING THIS PROBLEM, BUT ╔ THINK THIS IS A
GOOD PLACE FOR A QUICK-AND-DIRTY HACK. ╫HENEVER A USER PROCESS SENDS A
MESSAGE TO A MEMORY SERVER (BOTH LOCAL OR REMOTE, FOR WHATEVER REASON),
THROUGH THE MEMORY SERVERS' WELL-KNOWN ADDRESSES, THE BIT CORRESPONDING TO
THE MACHINE NUMBER (0-15) IN A SPECIAL 16-BIT FIELD OF THE SENDER'S PROCESS
CONTROL BLOCK IS SET. ╘HEN, WHEN THE PROCESS TERMINATES, THE TERMINATION
PROCEDURE (NEXT) PEEKS AT THIS SPECIAL FIELD AND SENDS FREE-ALL MESSAGES TO
ALL REMOTE MEMORY SERVERS THAT THE PROCESS IN QUESTION HAS INTERACTED WITH.
╘HIS INSURES THAT ALL MEMORY IN THE ENTIRE DISTRIBUTED SYSTEM THAT IS
ALLOCATED TO A PROCESS IS TIDIED UP WHEN THE PROCESS TERMINATES. ╠IKE THE
PROCESS SERVER, THE MEMORY SERVER IS INTEGRATED WITH THE KERNEL.
═╧╥┼ ╨╥╧├┼╙╙ ╘┼╥═╔╬┴╘╔╧╬
├OME TO THINK OF IT, ╔ SHOULD TALK MORE ABOUT PROCESS TERMINATION. ╘HE BEST
IDEA WOULD PROBABLY BE FOR A USER PROCESS TO TERMINATE ITSELF, IN THE SAME
WAY THAT IT BOOTSTRAPS ITSELF. ┴ TERMINATION MESSAGE IS SENT BY A CLIENT
PROCESS THAT WANTS TO KILL SOMEONE TO THE PROCESS SERVER. ╔T IS A VALID
SITUATION FOR A PROCESS TO COMMIT SUICIDE. ╘HE TERMINATION MESSAGE INCLUDES
THE PROCESS ID TO BE TERMINATED AND THE EXIT CODE FOR THE TERMINATION.
╘HE PROCESS SERVER THEN SUSPENDS THE DOOMED PROCESS' EXECUTION AND RIGS THE
PROCESS' CONTEXT SO THAT THE NEXT THING IT EXECUTES IS THE PROCESS SHUTDOWN
CODE INSIDE OF THE KERNEL. ╘HIS SHUTDOWN CODE CLOSES ALL OF THE FILES THAT
THE PROCESS HAS OPENED THROUGH THE STANDARD LIBRARY CALLS (AND OTHER SERVER-
RESOURCES HELD), DEALLOCATES ALL MEMORY HELD BY THE PROCESS, MAYBE DOES SOME
OTHER CLEANUP WORK, AND THEN SENDS A SPECIAL MESSAGE TO THE PROCESS SERVER TO
REMOVE THE PROCESS CONTROL BLOCK. ╘HE PROCESS SERVER WILL ONLY ACCEPT THIS
SPECIAL MESSAGE FROM THE PROCESS THAT IS TERMINATING AFTER THE FIRST PHASE OF
THE PROCESS SHUTDOWN HAS BEEN COMPLETED, TO INSURE A PROPER TERMINATION. ╘HE
PROCESS CONTROL BLOCK IS THEN DEALLOCATED AND MAY BE USED AGAIN. ╘HE PROCESS
SERVER IS THE ONLY PROCESS THAT IS ALLOWED TO MANIPULATE PROCESS CONTROL
BLOCKS.
├OME TO THINK OF IT, THERE IS A SLIGHT PROBLEM WITH PROCESS INITIALIZATION:
GETTING A COPY OF THE ARGUMENTS AND ENVIRONMENTAL VARIABLES FOR AN
ASYNCHRONOUSLY STARTED NEW PROCESS. ╫E DON'T WANT THE SENDER TO CONTINUE
BEFORE THE NEW PROCESS HAS HAD A CHANCE TO MAKE A COPY OF THE ARGUMENTS AND
ENVIRONMENT, SO WE WILL RIG THINGS SO THAT IT IS THE NEWLY STARTED PROCESS
THAT SENDS THE REPLY MESSAGE BACK TO THE PARENT PROCESS. ┴NOTHER DIRTY HACK.
2.7.3. ╞╔╠┼ ╙┼╥╓┼╥╙
┼ACH DISK DRIVE IN THE SYSTEM HAS A SPECIAL SERVER THAT PROVIDES AN INTERFACE
FOR EXECUTING ╧PEN, ╥EAD, ╫RITE, ├LOSE, AND A NUMBER OF OTHER COMMON FILE
OPERATIONS. ┴ BIG PROBLEM WITH DISTRIBUTED OPERATING SYSTEMS IS RESOURCE
RECLAMATION FOR PROCESSES THAT DIE. ╘HERE ARE A FEW WAYS TO PROVIDE THIS,
AND EACH HAS IMPLICATIONS ABOUT THE OVERALL DESIGN OF A SERVER.
╧NE POSSIBILITY IS TO HAVE "STATELESS SERVERS". ╔N OTHER WORDS, EACH SERVER
DOES NOT KEEP TRACK OF, FOR EXAMPLE, WHICH FILES A PROCESS HAS OPEN OR THE
CURRENT FILE POSITIONS. ┼ACH TIME A READ REQUEST COMES IN, THE SERVER OPENS
THE FILE TO BE USED, POSITIONS TO THE SECTION OF THE FILE, PERFORMS THE
OPERATION, AND CLOSES THE FILE AGAIN. ╘HIS SOUNDS LIKE A LOT OF WORK, BUT
SOME INTELLIGENT CACHING MAKES IT WORK EFFICIENTLY. ┴ND IF A USER PROCESS
DIES WITHOUT CLOSING ALL OF ITS FILES, IT DOESN'T MATTER SINCE THE FILES WILL
BE CLOSED ANYWAY, LOGICALLY AT THE COMPLETION OF EACH OPERATION. ┬UT, THIS
APPROACH DOESN'T REALLY WORK WELL WITH ├OMMODORE-─╧╙, WHICH WE WILL BE USING
FOR DEVICES FOR WHICH WE DON'T HAVE A CUSTOM DEVICE DRIVER, SO WE WON'T USE
IT.
┴NOTHER POSSIBILITY IS TO HAVE "SEMI-STATE" OR "ACKNOWLEDGEMENTLESS" SERVERS
(MY OWN INVENTION). ╚ERE, THE SERVER KEEPS TRACK OF, FOR EXAMPLE, WHICH
FILES ARE OPEN BUT DOESN'T KEEP THE FILE POSITION. ╫HEN A REQUEST COMES IN,
THE ALREADY-OPENED FILE IS POSITIONED ACCORDING TO THE REQUEST AND THE FILE
OPERATION TAKES PLACE. ╔F A CLIENT DIES UNEXPECTEDLY, THE OPEN FILE CONTROL
BLOCK (╞├┬) IS LEFT BEHIND, BUT THE ╞├┬ WILL BE CLOSED AND REUSED AFTER A
CERTAIN PERIOD OF TIME. ╔F THE CLIENT ACTUALLY HASN'T DIED, THEN THE
SITUATION WILL BE DETECTED (THROUGH DETAILS NOT EXPLAINED HERE) AND THE FILE
WILL BE REOPENED AS IF NOTHING HAS HAPPENED. ╧THER CONTINGENCIES LIKE A DEAD
PROCESS' NAME BEING REUSED ARE HANDLED TOO. ┴ND THE MODEL WORKS WELL WITH AN
UNRELIABLE COMMUNICATION SERVICE. ┬UT, AGAIN, THIS DOESN'T MODEL THE
├OMMODORE-─╧╙ VERY WELL.
╘HE FINAL DESIGN CONSIDERED IS TO HAVE A REGISTRY OF SERVERS THAT THAT A
PROCESS HAS RESOURCES CURRENTLY ALLOCATED ON BE ASSOCIATED WITH EACH PROCESS.
╫HEN A CLIENT MAKES AN OPEN REQUEST TO THE SERVER (OR SOME EQUIVALENT
RESOURCE-GRABBING OPERATION), THE SERVER CHECKS TO SEE IF THE CLIENT IS
CURRENTLY HOLDING ANY OTHER OF THE SERVER'S RESOURCES. ╔F SO, THEN THE
REQUEST IS PROCESSES NORMALLY. ╔F NOT, THEN THE SERVER (OR SOME AGENT ON THE
SERVER'S BEHALF) SENDS A MESSAGE TO THE PROCESS SERVER ON THE CLIENT'S
MACHINE TELLING THE PROCESS SERVER TO RECORD THE FACT THAT THE CLIENT IS (OR
MAY BE) HOLDING SOME OF THE SERVER'S RESOURCES. ╘HE PROCESS SERVER RECORDS
THE SERVER'S PROCESS ID IN THE PROCESS CONTROL BLOCK OF THE CLIENT, AND WHEN
THE CLIENT TERMINATES, IT WILL SEND A STANDARD "RELEASE ALL OF THE RESOURCES
THAT ╔ AM (MAY BE) HOLDING ON THIS SERVER" TO THE SERVER AS PART OF THE
CLIENT'S SHUTDOWN PROCEDURE. ┴LL OF THE CLIENT'S OPEN FILES WILL BE CLOSED,
ETC.
╔N THIS "REGISTRY" DESIGN, SERVERS CAN BE COMPLETELY "STATEFUL", E.G., THEY
WOULD CONTAIN BOTH AN OPEN FILE ENTRY AND THE FILE POSITION INFORMATION, AND
FILES WOULD ALWAYS OPEN AND CLOSE WHEN WE INTUITIVELY EXPECT THEM TO. ╔T IS
ASSUMED THAT THE COMMUNICATION MECHANISM IS RELIABLE, WHICH IT IS HERE. ╘HIS
MECHANISM *DOES* MODEL ├OMMODORE-─╧╙ WELL. ╔N FACT, THIS IDEA IS SO NICE
THAT ╔ MAY REDESIGN THE MEMORY ALLOCATION RECOVERY MECHANISM TO USE THIS.
╘HERE IS A SLIGHT POSSIBILITY OF A "RACE CONDITION" IN THIS MECHANISM, BUT
NOTHING BAD CAN HAPPEN BECAUSE OF IT. (╘HIS IS JUST A NOTE TO MYSELF: MAKE
IT SO THAT IF A PROCESS IS KILLED WHILE IT IS RECEIVE- OR REPLY-BLOCKED, THEN
IGNORE THE REPLY FROM THE SERVER IF THE PROCESS ID IS REUSED; DAMN, THERE'S
STILL A POTENTIAL PROBLEM; ╔'LL HAVE TO FIGURE IT OUT LATER; ALSO WATCH OUT
FOR A DISTRIBUTED DEADLOCK ON THE ╨├┬ LIST).
╙O, OUR SERVER SUPPORTS THE REGULAR FILE OPERATIONS AND IMPLEMENTS THEM IN
PRETTY MUCH THE EXPECTED WAY, SINCE IT IS A "STATEFUL" SERVER. ╘HE MAIN LOOP
OF THE SERVER ACCEPTS A REQUEST, DETERMINES WHICH TYPE IT IS, EXTRACTS THE
ARGUMENTS, CALLS THE APPROPRIATE LOCAL PROCEDURE, PREPARES THE REPLY MESSAGE,
REPLIES, AND GOES BACK TO THE TOP OF THE LOOP. ┼ACH OPENED FILE IS
IDENTIFIED BY A USER PROCESS BY A FILE CONTROL BLOCK NUMBER THAT HAS MEANING
INSIDE OF THE SERVER, AS PER USUAL. ┬UT, UNLIKE WITH ┴├┼, WE NEED A SPECIAL
"─UP" OPERATION FOR PASSING OPEN FILES TO CHILDREN. ─UP INCREMENTS THE
"REFERENCE COUNT" OF A ╞├┬, AND THE REFERENCE COUNT IS DECREMENTED EVERY TIME
A CLOSE OPERATION TAKES PLACE. ┴ FILE WILL ONLY BE "REALLY" CLOSED WHEN THE
REFERENCE COUNT REACHES ZERO. ╧UR SYSTEM WILL NOT IMPLEMENT ANY SECURITY AT
THIS TIME.
┬ECAUSE OF THE ABSTRACTION OF SENDING FORMATTED MESSAGES TO A SERVER,
DIFFERENT TYPES OF DISK DRIVES (├OMMODORE-─╧╙, CUSTOM-FLOPPY, RAMDISK) ARE
ALL DEALT WITH IN EXACTLY THE SAME WAY. ┴S ONE SLIGHT EXTENSION, WE HAVE TO
HACK OUR DEVICES (AT LEAST SOME OF THEM) A LITTLE TO BE ABLE TO HANDLE
"SYMBOLIC LINKS" IN ORDER TO INTEGRATE WELL WITH THE ╨REFIX ╙ERVER WHICH IS
DESCRIBED NEXT.
2.7.4. ╨╥┼╞╔╪ ╙┼╥╓┼╥
╘HE PREFIX SERVER IDEA IS STOLEN FROM THE COMPUTER SCIENCE LITERATURE ABOUT A
NETWORK OPERATING SYSTEM CALLED "╙PRITE". ╘HE PREFIX SERVER SIMPLY PROVIDES A
PATHNAME LOOKUP SERVICE FOR THE PATHNAMES OF DIFFERENT DISK-FILE AND DEVICE
SERVERS. ╘HIS IS NEEDED TO PROVIDE A SINGLE, GLOBAL, UNIFIED PATHNAME SPACE
ON A SYSTEM OF MULTIPLE DISTRIBUTED FILE SERVERS. ╔T WORKS A LOT LIKE THE
"MOUNT TABLE" IN ╒NIX. ╔TS PREFIX TABLE LOOKS SOMETHING LIKE THE FOLLOWING:
╨╥┼╞╔╪ ╙┼╥╓┼╥
------ ------
/ <1:RAMDISK>
/DEV/TTY0 <1:CONSOLE>
/FD1 <2:FLOPPY1571>
┬╘╫, ┬╧╙ USES ╒NIX-STYLE FILENAMES RATHER THAN THE ├REATIVE-═ICRO-─ESIGNS-
STYLE FILENAMES THAT ┴├┼ USES.
╔F AN APPLICATION IS GIVEN AN ABSOLUTE PATHNAME, IT WILL CONSULT THE PREFIX
SERVER TO RESOLVE IT TO THE PROCESS-ID OF AN ACTUAL SERVER. ╞OR EXAMPLE, THE
PATHNAME "/FD1/BOB/FRED" WOULD RESOLVE TO SERVER "<2:FLOPPY1571>", RELATIVE
PATHNAME "BOB/FRED". ╨ATHNAME "/" WOULD RESOLVE TO SERVER "<1:RAMDISK>",
RELATIVE PATHNAME "".
╘HE USER PROCESS WOULD THEN CONTACT THE APPROPRIATE SERVER WITH THE RELATIVE
PATHNAME. ┴ USER PROCESS CAN ASSUME THAT THE PREFIX TABLE WILL NOT CHANGE
WHILE THE SYSTEM IS RUNNING, SO SOME INTELLIGENT CACHING CAN BE DONE. ┴LSO,
DIRECTORY TOKENS ARE GIVEN OUT FOR EXECUTING A "CHANGE DIRECTORY" OPERATION,
AND THESE SERVER/TOKEN PAIRS CAN BE USED FOR QUICK RELATIVE PATHNAME
SEARCHES. ┴ SYMBOLIC LINK MECHANISM IS NEEDED TO INSURE THAT THESE RELATIVE
SEARCHES ALWAYS FOLLOW THROUGH CORRECTLY.
2.7.5. ─┼╓╔├┼ ╙┼╥╓┼╥╙
─EVICE SERVERS ARE JUST ANOTHER TYPE OF FILE SERVER, EXCEPT THEY CONTROL A
SPECIFIC DEVICE OTHER THAN A REGULAR DISK DEVICE, AND THEY ARE LIKELY TO
SUPPORT SOME CUSTOM OPERATIONS AND RETURN ERROR CODES IF SOME DISK OPERATIONS
ARE ATTEMPTED. ╘HE INTERFACE IS IDENTICAL TO A FILE SERVER FOR CONVENIENCE.
2.7.6. ├╧╬╙╧╠┼ ╙┼╥╓┼╥
╩UST A SPECIFIC DEVICE SERVER. ╔T HANDLES WINDOW MANAGEMENT AND CONSOLE
CALLS, LIKE ╫IN├LEAR, ╫IN╨UT, ╟ET╦EY, AND ├ON╫RITE, THAT ARE USED IN ┴├┼.
2.8. ┴╙┘╬├╚╥╧╬╧╒╙ ┼╓┼╬╘ ╚┴╬─╠╔╬╟
┴S MENTIONED IN THE ╨ROCESS SECTION ABOVE, THERE ARE MANY EXTERNAL EVENTS
THAT A PROCESS MAY HAVE TO WAIT FOR, INCLUDING: MODEM CHARACTERS, DISK DRIVE
OPERATIONS (IF THEY ARE CUSTOM-PROGRAMMED CORRECTLY), MOUSE & JOYSTICK
MOVEMENTS, AND REAL-TIME DELAYS. ╘HERE WILL BE AN ┴WAIT┼VENT() KERNEL
PRIMITIVE TO ALLOW A PROCESS TO WAIT FOR ONE OF THESE EVENTS TO HAPPEN.
╬ORMALLY, THE ONLY PROCESSES THAT WAIT FOR THESE EVENTS WILL BE DEVICE
DRIVERS. ╘HE KERNEL WILL ALSO HAVE TO DO SOME LOW-LEVEL PROCESSING FOR OF
SOME DEVICES (LIKE THE MODEM AND KEYBOARD) TO INSURE THAT THINGS DON'T BECOME
UNNECESSARILY INEFFICIENT.
3. ╦┼╥╬┼╠ ─┼╙╔╟╬
╬EXT TIME.
4. ╙┘╙╘┼═ ╙┼╥╓┼╥ ─┼╙╔╟╬
╬EXT TIME.
5. ┴╨╨╠╔├┴╘╔╧╬ ╨╥╧╟╥┴═ ╔╬╘┼╥╞┴├┼
╬EXT TIME.
╘HIS IS QUITE SIMILAR TO THE ┴├┼-128/64 ╨ROGRAMMER'S ╥EFERENCE ╟UIDE, WHICH
IS AVAILABLE VIA ANONYMOUS ╞╘╨ FROM "CCNGA.UWATERLOO.CA" IN FILE
"/PUB/CBM/OS/ACE/ACE-R10-PRG.DOC". ╥ELEASE #10 OF ┴├┼ WAS THE MOST CURRENT
AT THE TIME OF WRITING THIS ARTICLE.
6. ├╧╬├╠╒╙╔╧╬
╬EXT TIME.
╔MPLEMENTATION: SOMEDAY, MAYBE.
==================================================================---┼╬─---===